Heim  >  Artikel  >  Web-Frontend  >  Vertieftes Verständnis des Konzepts von Prototypen in der JavaScript-Programmierung_Grundkenntnisse

Vertieftes Verständnis des Konzepts von Prototypen in der JavaScript-Programmierung_Grundkenntnisse

WBOY
WBOYOriginal
2016-05-16 15:53:051087Durchsuche

Die Prototypobjekte von JavaScript sind immer verwirrend. Selbst erfahrene JavaScript-Experten und sogar seine Autoren geben oft eine sehr begrenzte Erklärung dieses Konzepts. Ich glaube, das Problem liegt in unserem frühesten Verständnis von Prototypen. Prototypen sind immer eng mit den Eigenschaften Neu, Konstrukteur und der verwirrenden Prototypeneigenschaft verbunden. Tatsächlich ist Prototyping ein ziemlich einfaches Konzept. Um es besser zu verstehen, müssen wir die Konstruktionsarchetypen, die wir „gelernt“ haben, verlernen und dann zu den Wurzeln zurückkehren.

Was ist ein Prototyp?

Ein Prototyp ist ein Objekt, das Eigenschaften von anderen Objekten erbt.

Kann jedes Objekt ein Prototyp sein?

Ja

Diese Objekte haben Prototypen?

Jedes Objekt hat einen Standardprototyp. Prototypen selbst sind Objekte, und jeder Prototyp selbst hat einen Prototyp. (Mit einer Ausnahme steht der Standardobjektprototyp an der Spitze jeder Prototypenkette und die anderen Prototypen am Ende der Prototypenkette)

Einen Schritt zurücktreten: Was ist ein Objekt?

In JavaScript ist ein Objekt eine beliebige ungeordnete Sammlung, die als Schlüssel-Wert-Paare gespeichert wird. Wenn es sich nicht um eine primitive Klasse (undefiniert, null, boolean.nuber oder string) handelt, handelt es sich um ein Objekt.

Sie können denken, dass jedes Objekt einen Prototyp hat, aber als ich ({}).prototype schrieb, wurde ich undefiniert.

Vergessen Sie alles, was Sie über die Prototyp-Eigenschaft wissen – das ist wahrscheinlich eine Quelle der Verwirrung. Der wahre Prototyp eines Objekts ist die interne [[Prototype]]-Eigenschaft. . Diese neueste Implementierung wird von Firefox, Safari, Chrome und IE9 unterstützt. Darüber hinaus unterstützen alle Browser die nicht standardmäßige Zugriffsmethode __proto__. Ansonsten können wir nur sagen, dass der Konstruktor eines Objekts seine Prototypeigenschaften sind.

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]


Sehr gut, false ist ein primitiver Typ. Warum gibt false.__proto__ einen Wert zurück?

Beim Zugriff auf den Prototyp eines primitiven Typs wird dieser in ein Objekt umgewandelt.

//(works in IE<=8 too, due to double-negative)
false.__proto__ === Boolean(false).__proto__; //true

Ich möchte die Vererbung mithilfe von Prototypen implementieren. Was soll ich jetzt tun?

Es ist fast bedeutungslos, einer Instanz Prototypeigenschaften hinzuzufügen, es sei denn, es gibt eine Situation, in der es sehr effizient ist, Eigenschaften direkt zur Instanz selbst hinzuzufügen . Funktion. Zum Beispiel Array, wir können dies tun

//fails in IE<=8
var a = {};
a.__proto_ = Array.prototype;
a.length; //0

Aber wir können sehen, dass die wahre Stärke von Prototypen darin liegt, dass mehrere Instanzen denselben Prototyp teilen. Eigenschaften eines Prototypobjekts werden einmal definiert und von allen Instanzen, auf die es verweist, geerbt. Die Verbesserung der Leistung und Wartbarkeit des Programms durch die Verwendung von Prototypen ist offensichtlich. Ist das also der Grund für den Konstruktor? Ja, Konstruktoren bieten einen praktischen browserübergreifenden Mechanismus für die gemeinsame Prototypenzuweisung bei der Instanzerstellung. .


Bevor ich ein Beispiel gebe, muss ich wissen, was die Eigenschaft „constructor.prototype“ bewirkt?

Nun, zunächst einmal unterscheidet JavaScript nicht zwischen Konstruktoren und anderen Methoden, daher hat jede Methode ein Prototypattribut. Im Gegenteil, alles, was keine Methode ist, verfügt nicht über solche Attribute.

//永远不是构造函数的方法,无论如何都是有prototype属性的
Math.max.prototype; //[object Object]
 
//构造函数也有prototype属性
var A = function(name) {
  this.name = name;
}
A.prototype; //[object Object]
 
//Math不是一个方法,所以没有prototype属性
Math.prototype; //null

Jetzt können Sie Folgendes definieren: Das Prototypattribut einer Methode ist das Prototypobjekt, das der Instanz zugewiesen wird, wenn diese Methode als Konstruktor zum Erstellen einer Instanz verwendet wird.

Es ist sehr wichtig zu verstehen, dass das Prototypattribut einer Methode nichts mit dem tatsächlichen Prototyp zu tun hat.

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

Können Sie ein Beispiel nennen?

Sie haben den folgenden Code vielleicht schon hunderte Male gesehen oder verwendet, aber hier ist er noch einmal, aber möglicherweise gibt es etwas Neues.

//构造器. <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

Das ist großartig. Wenn ich die Prototypeigenschaft des Konstruktors ändere, können dann sogar vorhandene Instanzobjekte sofort auf die neue Prototypenversion zugreifen?

Hmm... nicht wirklich. Wenn ich die Attribute eines vorhandenen Prototyps ändere, ist dies tatsächlich der Fall, da a.__proto__ auf das von A.prototype definierte Objekt verweist, wenn das Objekt erstellt wird.

var A = function(name) {
  this.name = name;
}
 
var a = new A('alpha');
a.name; //'alpha'
 
A.prototype.x = 23;
 
a.x; //23


Aber wenn ich das Prototyp-Attribut durch ein neues Objekt ersetze, zeigt a.__proto__ immer noch auf das ursprüngliche Objekt.

var A = function(name) {
  this.name = name;
}
 
var a = new A('alpha');
a.name; //'alpha'
 
A.prototype = {x:23};
 
a.x; //null

Wie sieht ein Standardprototyp aus?

Ein Objekt mit Konstruktoreigenschaft.

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


Welche Beziehung besteht zwischen Instanz und Prototyp?
Wenn das Prototyp-Attribut von A in der Prototyp-Kette von a erscheint, gibt der Ausdruck eine Instanz von A „true“ zurück. Das bedeutet, dass wir die Instanz von zum Scheitern bringen können.

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


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

记得我曾经说过每一个构造器都拥有一个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..."

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


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

a.__proto__ = b;
b.__proto__ = c;
c.__proto__ = {}; //默认对象
{}.__proto__.__proto__; //null


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

直接赋值会咋样?

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

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn