Quelle est la différence?
var A = function () {
this.x = function () {
//do something
};
};
ou
var A = function () { };
A.prototype.x = function () {
//do something
};
Quelle est la différence?
var A = function () {
this.x = function () {
//do something
};
};
ou
var A = function () { };
A.prototype.x = function () {
//do something
};
Les exemples ont des résultats très différents.
Avant de regarder les différences, les points suivants doivent être notés:
[[Prototype]]
de la propriété.myObj.method()
) alors ce à l'intérieur de la méthode références de l'objet. Où ce n'est pas définie par l'appel ou par l'utilisation de bind, la valeur par défaut de l'objet global (de la fenêtre dans un navigateur) ou en mode strict, reste indéfini.Voici donc les extraits de code en question:
var A = function () {
this.x = function () {
//do something
};
};
Dans ce cas, la variable A
est affectée une valeur qui est une référence à une fonction. Lorsque cette fonction est appelée à l'aide d' A()
, la fonction, ce n'est pas définie par l'appel, afin que la valeur par défaut de l'objet global et l'expression this.x
est efficacement window.x
. Le résultat est qu'une référence à l'expression de fonction sur le côté droit est affecté à l' window.x
.
Dans le cas de:
var A = function () { };
A.prototype.x = function () {
//do something
};
quelque chose de très différent se produit. Dans la première ligne, la variable A
est attribué une référence à une fonction. En JavaScript, toutes les fonctions, les objets ont un prototype de propriété par défaut, il n'y a pas de code pour créer un A. prototype de l'objet.
Dans la deuxième ligne, A. prototype.x est affecté à une référence à une fonction. Cela va créer une x de la propriété si elle n'existe pas, ou assigner une nouvelle valeur si elle n'. Donc, la différence avec le premier exemple est l'objet dont l' x de la propriété est impliqué dans l'expression.
Un autre exemple est ci-dessous. Il est similaire à la première (et peut-être ce que tu voulais dire à propos):
var A = new function () {
this.x = function () {
//do something
};
};
Dans cet exemple, l' new
de l'opérateur a été ajouté avant l'expression de fonction, de sorte que la fonction est appelée en tant que constructeur. Lorsqu'elle est appelée avec new
, la fonction de ce est configuré pour faire référence à un Objet dont le privé [[Prototype]]
propriété a la valeur de référence par le constructeur public prototype. Ainsi, dans l'instruction d'affectation, l' x
de la propriété sera créé sur ce nouvel objet. Lorsqu'il est appelé en tant que constructeur, une fonction retourne sa cet objet par défaut, donc il n'est pas nécessaire de séparer return this;
déclaration.
Pour vérifier qu' Un a un x de la propriété:
console.log(A.x) // function () {
// //do something
// };
C'est rare de l'utiliser de nouveau, puisque le seul moyen de référence est le constructeur par A. constructeur. Il serait beaucoup plus fréquent de faire:
var A = function () {
this.x = function () {
//do something
};
var a = new A();
Une autre façon de parvenir à un résultat similaire est d'utiliser un immédiatement appelé la fonction de l'expression:
var A = (function () {
this.x = function () {
//do something
};
}());
Dans ce cas, A
affecté la valeur de retour de l'appel de fonction sur le côté droit. Ici, de nouveau, car ce n'est pas définie dans l'appel, il fait référence à l'objet global et this.x
est efficacement window.x
. Puisque la fonction ne retourne rien, A
auront une valeur de undefined
.
Questions connexes:
Note: Il ne peut pas y avoir d'importantes économies de mémoire entre les deux approches, cependant en utilisant le prototype de partager des méthodes et des propriétés susceptibles d'utiliser moins de mémoire que chaque instance d'avoir sa propre copie.
JavaScript n'est pas un langage de bas niveau. Il peut ne pas être très précieux pour penser le prototypage ou d'autres modes de transmission comme un moyen de modifier explicitement la façon dont la mémoire est allouée.
Comme d'autres l'ont dit la première version, l'utilisation de "ce" des résultats à chaque instance de la classe A, de son propre copie indépendante de la méthode de la fonction "x". Tandis que l'utilisation de "prototype" signifie que chaque instance de la classe A pour utiliser la même copie de la méthode "x".
Voici un peu de code pour montrer cette différence subtile:
// x is a method assigned to the object using "this"
var A = function () {
this.x = function () {
alert('A');
};
};
A.prototype.updateX = function(value) {
this.x = function() {
alert(value);
}
};
var a1 = new A();
var a2 = new A();
a1.x(); // Displays 'A'
a2.x(); // Also displays 'A'
a1.updateX('Z');
a1.x(); // Displays 'Z'
a2.x(); // Still displays 'A'
// Here x is a method assigned to the object using "prototype"
var B = function () { };
B.prototype.x = function () {
alert('B');
};
B.prototype.updateX = function(value) {
B.prototype.x = function() {
alert(value);
}
}
var b1 = new B();
var b2 = new B();
b1.x(); // Displays 'B'
b2.x(); // Also displays 'B'
b1.updateX('Y');
b1.x(); // Displays 'Y'
b2.x(); // Also displays 'Y' because by using prototype we
// have changed it for all instances
Comme d'autres l'ont mentionné, il y a plusieurs raisons pour choisir une méthode ou l'autre. Mon échantillon est juste pour démontrer clairement la différence.
Dans la plupart des cas, ils sont essentiellement les mêmes, mais la deuxième version permet d'économiser la mémoire, car il n'y a qu'une seule instance de la fonction au lieu d'une fonction distincte pour chaque objet.
Une raison de l'utiliser la première forme est celle de l'accès "privé". Par exemple:
var A = function () {
var private_var = ...;
this.x = function () {
return private_var;
};
this.setX = function (new_x) {
private_var = new_x;
};
};
En raison de règles de portée de javascript, private_var est disponible pour la fonction qui lui est assignée.x, mais pas à l'extérieur de l'objet.
L'ultime problème avec l'aide d' this
au lieu de prototype
, c'est que lors du remplacement d'une méthode, le constructeur de la classe de base va encore se référer à la méthode de remplacement. Réfléchissez à ceci:
BaseClass = function() {
var text = null;
this.setText = function(value) {
text = value + " BaseClass!";
};
this.getText = function() {
return text;
};
this.setText("Hello"); // This always calls BaseClass.setText()
};
SubClass = function() {
// setText is not overridden yet,
// so the constructor calls the superclass' method
BaseClass.call(this);
// Keeping a reference to the superclass' method
var super_setText = this.setText;
// Overriding
this.setText = function(value) {
super_setText.call(this, "SubClass says: " + value);
};
};
SubClass.prototype = new BaseClass();
var subClass = new SubClass();
console.log(subClass.getText()); // Hello BaseClass!
subClass.setText("Hello"); // setText is already overridden
console.log(subClass.getText()); // SubClass says: Hello BaseClass!
contre:
BaseClass = function() {
this.setText("Hello"); // This calls the overridden method
};
BaseClass.prototype.setText = function(value) {
this.text = value + " BaseClass!";
};
BaseClass.prototype.getText = function() {
return this.text;
};
SubClass = function() {
// setText is already overridden, so this works as expected
BaseClass.call(this);
};
SubClass.prototype = new BaseClass();
SubClass.prototype.setText = function(value) {
BaseClass.prototype.setText.call(this, "SubClass says: " + value);
};
var subClass = new SubClass();
console.log(subClass.getText()); // SubClass says: Hello BaseClass!
Si vous pensez que ce n'est pas un problème, cela dépend si vous pouvez vivre sans variables privées, et si vous avez assez d'expérience pour savoir qu'une fuite quand vous voyez un. Aussi, avoir à mettre de la logique constructeur après les définitions de méthode n'est pas pratique.
var A = function (param1) {
var privateVar = null; // Private variable
// Calling this.setPrivateVar(param1) here would be an error
this.setPrivateVar = function (value) {
privateVar = value;
console.log("setPrivateVar value set to: " + value);
// param1 is still here, possible memory leak
console.log("setPrivateVar has param1: " + param1);
};
// The constructor logic starts here possibly after
// many lines of code that define methods
this.setPrivateVar(param1); // This is valid
};
var a = new A(0);
// setPrivateVar value set to: 0
// setPrivateVar has param1: 0
a.setPrivateVar(1);
//setPrivateVar value set to: 1
//setPrivateVar has param1: 0
contre:
var A = function (param1) {
this.setPublicVar(param1); // This is valid
};
A.prototype.setPublicVar = function (value) {
this.publicVar = value; // No private variable
};
var a = new A(0);
a.setPublicVar(1);
console.log(a.publicVar); // 1
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.