2016-12-16 2 views
0

Vous trouverez ci-dessous deux façons de définir des méthodes sur des objets créés avec le mot clé new. J'essaie de comparer les fonctionnements et les effets de chacun.Comment fonctionne fun.call lorsque la valeur de thisArg fournie pour l'appel à fun est un objet Function.prototype?

1) Un mélange fonctionnel asCircle est défini. Puis .call injecte le mélange dans Circle.prototype par délégation. L'effet est que les new Circle instances ont maintenant des méthodes telles que .area mélangés.

var asCircle = function() { 
 
     this.area = function() { 
 
     return Math.PI * this.radius * this.radius; 
 
     }; 
 
     this.grow = function() { 
 
     this.radius++; 
 
     }; 
 
     this.shrink = function() { 
 
     this.radius--; 
 
     }; 
 
     return this; 
 
    }; 
 
     
 
    var Circle = function(radius) { 
 
     this.radius = radius; 
 
    }; 
 
    asCircle.call(Circle.prototype); 
 
    var circle1 = new Circle(5); 
 
    var circle2 = new Circle(6); 
 

 
    console.log(circle1.area());

2) Une fonction Circle est défini comme un constructeur avec une propriété radius. Les fonctions sont ensuite affectées aux propriétés Circle.prototype. Effectivement toutes les instances new Circle peuvent maintenant appeler ces méthodes par exemple .area().

var Circle = function(radius) { 
 
    this.radius = radius; 
 
    }; 
 
    Circle.prototype.area = function() { 
 
    return Math.PI * this.radius * this.radius; 
 
    }; 
 
    Circle.prototype.grow = function() { 
 
    this.radius++; 
 
    }; 
 
    Circle.prototype.shrink = function() { 
 
    this.radius--; 
 
    }; 
 

 
    var circle1 = new Circle(5); 
 
    var circle2 = new Circle(6); 
 

 
    console.log(circle1.area());

En voyant la mise en œuvre 1 J'ai été surpris de voir que .area pourrait être réutilisé sur tout nouveau Cercle simplement en appelant la fonction asCircle avec Circle.prototype comme thisArg.

Pourquoi est l'effet de l'utilisation de la mise en œuvre .call 1 la même que la définition de ces méthodes directement sur Circle.prototype comme dans la mise en œuvre 2?

Répondre

1

Dans le premier extrait de code

1 .'Call » modifie le contexte de 'ceci'. Lorsque vous appelez asCircle.call (Circle.prototype), asCircle est appelée avec « ce » étant Circle.prototype

2.Tous la zone méthodes/croître et se contracter sont ajoutés au prototype qui a même effet que votre deuxième extrait de code

Hope this helps

1

Pourquoi l'effet de l'utilisation .call dans la mise en œuvre 1 la même que la définition de ces méthodes directement sur Circle.prototype comme dans la mise en œuvre 2?

Function.prototype.call permet de définir la valeur this sur le premier argument.

asCircle.call(Circle.prototype) définit this dans asCircle à Circle.prototype.

// so now when you see ... 
this.area = function() { 
    return Math.PI * this.radius * this.radius; 
}; 

// it's the same as ... 
Circle.prototype.area = function() { 
    return Math.PI * this.radius * this.radius; 
} 

Mais le this intérieur de la fonction area est un this différent parce qu'il est entré dans une nouvelle fonction.La valeur de cette this est déterminée lorsque cette fonction est appelée: Par exemple, circle1.area(); définit la valeur de this dans area à circle1

// so now when you see ... 
return Math.PI * this.radius * this.radius; 

// it's the same as ... 
return Math.PI * circle1.radius * circle1.radius 

Remarques

Et maintenant que vous avez appris pour écrire du code que vous ne devriez jamais utiliser. Voici une mise en œuvre sensible de Circle en utilisant deux techniques

classe ES6 (ce qui est essentiellement la même chose que votre méthode 2)

class Circle { 
    constructor(radius) { 
    this.radius = radius 
    } 
    area() { 
    return Math.PI * this.radius * this.radius 
    } 
    grow() { 
    this.radius++ 
    } 
    shrink() { 
    this.radius-- 
    } 
} 

Ou d'une manière fonctionnelle en utilisant l'abstraction de données. Notez l'absence de this et combien votre vie est plus facile à cause de cela.

const makeCircle = r => ({radius: r}) 
const circleRadius = c => c.radius 
const circleArea = c => Math.PI * circleRadius(c) * circleRadius(c) 
const circleGrow = c => makeCircle(circleRadius(c) + 1) 
const circleShrink = c => makeCircle(circleRadius(c) - 1)) 
0

Compte tenu des objets suivants:

o = {}; 
f = function() { 
    this.s = "hello"; 
}; 

f.call(o) moyens call f with this = o. Ainsi, f.call(o) est exactement le même que o.s = "hello". L'effet des deux implémentations est le même parce que this et o sont les mêmes, c'est aussi simple que cela :-P

La vraie question est, quelle est la magie derrière l'héritage prototypique? En termes simples, pourquoi une fonction qui appartient au prototype de Circle est appelable à partir d'une instance de Circle? Ceci est dû au fait que JavaScript (en fait, tout langage orienté objet qui fournit l'héritage à l'exécution) implémente ce que l'on appelle un mécanisme de recherche. Lorsqu'une méthode n'est pas trouvée dans un objet, JavaScript continuera à chercher dans le prototype de cet objet, puis dans le prototype de son prototype, et ainsi de suite, jusqu'à la fin de la chaîne.

// Person is the parent class of President 
Person = function (name) { this.name = name; }; 
Person.prototype.iam = function() { return this.name; }; 

// President is a subclass of Person 
President = function() { Person.apply(this, arguments); }; 
President.prototype = new Person(); 

// trump is an instance of President and Person 
trump = new President("Donald"); 
trump.iam(); // "Donald" (ok) 
trump.hasOwnProperty("iam"); // false (wtf!) 
President.prototype.hasOwnProperty("iam"); // false (WTF!!) 
Person.prototype.hasOwnProperty("iam"); // true (finally...) 

Bonus (Object est la classe parente de tout):

Object.prototype.hasOwnProperty("hasOwnProperty"); // true