Maison > interface Web > js tutoriel > Compréhension approfondie du concept de prototypes en programmation JavaScript_Connaissances de base

Compréhension approfondie du concept de prototypes en programmation JavaScript_Connaissances de base

WBOY
Libérer: 2016-05-16 15:53:05
original
1119 Les gens l'ont consulté

Les objets prototypes de JavaScript prêtent toujours à confusion. Même les experts JavaScript expérimentés et même ses auteurs donnent souvent une explication très limitée de ce concept. Je pense que le problème vient de notre première compréhension des prototypes. Les prototypes sont toujours étroitement associés au nouveau, au constructeur et à la propriété déroutante du prototype. En fait, le prototypage est un concept assez simple. Pour mieux le comprendre, nous devons désapprendre les archétypes de construction que nous avons « appris » et ensuite revenir aux racines.

Qu'est-ce qu'un prototype ?

Un prototype est un objet qui hérite des propriétés d'autres objets.

Tout objet peut-il être un prototype ?

Oui

Ces objets ont des prototypes ?

Chaque objet a un prototype par défaut. Les prototypes eux-mêmes sont des objets, et chaque prototype possède lui-même un prototype. (À une exception près, le prototype d'objet par défaut se trouve en haut de chaque chaîne de prototypes, et les autres prototypes sont en fin de chaîne de prototypes)

En prenant du recul, qu'est-ce qu'un objet ?

En JavaScript, un objet est une collection arbitraire non ordonnée enregistrée sous forme de paires clé-valeur. S'il ne s'agit pas d'une classe primitive (indéfinie, nulle, boolean.nuber ou chaîne), c'est un objet.

Vous pouvez penser que chaque objet a un prototype. Mais quand j'ai écrit ({}).prototype, je suis devenu indéfini. Êtes-vous fou ?

Oubliez tout ce que vous savez sur la propriété prototype - c'est probablement une source de confusion. Le véritable prototype d'un objet est la propriété interne [[Prototype]] introduit la méthode d'accès standard, Object.getPrototypeOf(object ). . Cette dernière implémentation est prise en charge par Firefox, Safari, Chrome et IE9 De plus, à l'exception d'IE, tous les navigateurs prennent en charge la méthode d'accès non standard __proto__ Sinon, on peut seulement dire que le constructeur d'un objet est son prototype Propriétés.

var a = {};
 
//Opera 或 IE<=8下失败
Object.getPrototypeOf(a); //[object Object]
 
//IE下失败
a.__proto__; //[object Object]
 
//所有浏览器
//(but only if constructor.prototype has not been replaced and fails with Object.create)
a.constructor.prototype; //[object Object]
Copier après la connexion


Très bien, false est un type primitif, pourquoi false.__proto__ renvoie-t-il une valeur ?

Lors de l'accès au prototype d'un type primitif, il sera contraint en objet.



//(works in IE<=8 too, due to double-negative)
false.__proto__ === Boolean(false).__proto__; //true
Copier après la connexion

Je souhaite implémenter l'héritage à l'aide de prototypes, que dois-je faire maintenant ?

Cela n'a presque aucun sens d'ajouter des propriétés de prototype à une instance. Sauf s'il existe une situation, c'est-à-dire qu'il est très efficace d'ajouter des propriétés directement à l'instance elle-même. Supposons que nous ayons déjà un objet et que nous souhaitions partager l'objet existant. . Fonction. Par exemple Array, nous pouvons faire cela

.

//fails in IE<=8
var a = {};
a.__proto_ = Array.prototype;
a.length; //0
Copier après la connexion
Mais nous pouvons voir que la véritable puissance des prototypes réside dans plusieurs instances partageant le même prototype. Les propriétés d'un objet prototype sont définies une seule fois et sont héritées par toutes les instances auxquelles il fait référence. L'amélioration des performances et de la maintenabilité du programme grâce à l'utilisation de prototypes est évidente. Alors est-ce la raison du constructeur ? Oui, les constructeurs fournissent un mécanisme multi-navigateur pratique pour l'attribution de prototypes communs lors de la création d'instances. .


Avant de donner un exemple, j'ai besoin de savoir à quoi sert la propriété constructor.prototype ?

Eh bien, tout d'abord, JavaScript ne fait pas de distinction entre les constructeurs et les autres méthodes, donc chaque méthode a un attribut prototype. Au contraire, tout ce qui n’est pas une méthode ne possède pas de tels attributs.



//永远不是构造函数的方法,无论如何都是有prototype属性的
Math.max.prototype; //[object Object]
 
//构造函数也有prototype属性
var A = function(name) {
  this.name = name;
}
A.prototype; //[object Object]
 
//Math不是一个方法,所以没有prototype属性
Math.prototype; //null
Copier après la connexion
Vous pouvez maintenant définir : L'attribut prototype d'une méthode est l'objet prototype attribué à l'instance lorsque cette méthode est utilisée comme constructeur pour créer une instance.

Il est très important de comprendre que l'attribut prototype d'une méthode n'a rien à voir avec le prototype réel.



//(在IE中会失败)
var A = function(name) {
  this.name = name;
}
 
A.prototype == A.__proto__; //false
A.__proto__ == Function.prototype; //true - A的prototype是它的构造函数的prototype属性
Copier après la connexion

Pouvez-vous donner un exemple ?

Vous avez peut-être vu ou utilisé le code suivant des centaines de fois, mais le voici à nouveau, mais il peut y avoir quelque chose de nouveau.



//构造器. <em>this</em> 作为新对象返回并且它内部的[[prototype]]属性将被设置为构造器默认的prototype属性
var Circle = function(radius) {
  this.radius = radius;
  //next line is implicit, added for illustration only
  //this.__proto__ = Circle.prototype;
}
 
//扩充 Circle默认的prototype对象的属性因此扩充了每个由它新建实例的prototype对象的属性
Circle.prototype.area = function() {
  return Math.PI*this.radius*this.radius;
}
 
//创建Circle的两个示例,每个都会使用相同的prototype属性
var a = new Circle(3), b = new Circle(4);
a.area().toFixed(2); //28.27
b.area().toFixed(2); //50.27
Copier après la connexion
C'est génial. Si je modifie la propriété prototype du constructeur, même les objets d'instance existants peuvent-ils accéder immédiatement à la nouvelle version du prototype ?

Hmm... pas vraiment. Si je modifie les attributs d'un prototype existant, alors c'est bien le cas, car a.__proto__ fait référence à l'objet défini par A.prototype lors de la création de l'objet.



var A = function(name) {
  this.name = name;
}
 
var a = new A('alpha');
a.name; //'alpha'
 
A.prototype.x = 23;
 
a.x; //23
Copier après la connexion

Mais si je remplace l'attribut prototype par un nouvel objet, a.__proto__ pointe toujours vers l'objet d'origine.


var A = function(name) {
  this.name = name;
}
 
var a = new A('alpha');
a.name; //'alpha'
 
A.prototype = {x:23};
 
a.x; //null
Copier après la connexion

À quoi ressemble un prototype par défaut ?

Un objet avec la propriété constructeur.



var A = function() {};
A.prototype.constructor == A; //true
 
var a = new A();
a.constructor == A; //true (a 的constructor属性继承自它的原型)
Copier après la connexion


Quelle est la relation entre instanceof et prototype ?
Si l'attribut prototype de A apparaît dans la chaîne prototype de a, l'expression une instance de A retournera vrai. Cela signifie que nous pouvons tromper instanceof pour qu'il échoue.


var A = function() {}
 
var a = new A();
a.__proto__ == A.prototype; //true - so instanceof A will return true
a instanceof A; //true;
 
//mess around with a's prototype
a.__proto__ = Function.prototype;
 
//a's prototype no longer in same prototype chain as A's prototype property
a instanceof A; //false
Copier après la connexion


那么我还能利用原型干些其它的什么事儿?

记得我曾经说过每一个构造器都拥有一个prototype属性,利用该属性可以将原型赋值给所有由构造器产生的实例?其实这同样适用于本地构造器,例如Function和String。通过扩展(而不是替换)这个属性,我们可以更新每个指定类型对象的prototype。

String.prototype.times = function(count) {
  return count < 1 &#63; '' : new Array(count + 1).join(this);
}
 
"hello!".times(3); //"hello!hello!hello!";
"please...".times(6); //"please...please...please...please...please...please..."
Copier après la connexion

告诉我更多关于继承与原型是怎么工作的。原型链又是什么东东?


因为每个对象和每个原型(本身)都有一个原型,我们可以想象, 一个接一个的对象连接在一起形成一个原型链。 原型链的终端总是默认对象(object)的原型。

a.__proto__ = b;
b.__proto__ = c;
c.__proto__ = {}; //默认对象
{}.__proto__.__proto__; //null
Copier après la connexion


原型继承机制是内在且隐式实现的。当对象a要访问属性foo时,Javascript会遍历a的原型链(首先从a自身开始),检查原型链的每一个环节中存在的foo属性。如果找到了foo属性就会将其返回,否则返回undefined值。

直接赋值会咋样?

当直接为对象属性赋值时,原型继承机制就玩不转了。a.foo='bar'会直接赋值给a的foo属性。要想为原型对象的属性赋值,你需要直接定位原型对象的该属性。
关于javascript原型就讲全了。我觉得对于原型概念的理解,我把握的还是比较准确的,但是我的观点无论如何也不是最后的结果。请随便告之我的错误之处或提出和我不一致的观点。

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal