Heim > Web-Frontend > js-Tutorial > Hauptteil

Vertiefendes Verständnis der Codebeispiele für JavaScript-Prototypkonzepte (Bild)

黄舟
Freigeben: 2017-03-11 14:44:57
Original
1535 Leute haben es durchsucht

Prototyp ist ein schwer zu verstehendes Konzept in JavaScript. Es gibt viele Attribute im Zusammenhang mit Prototypen. Objekte haben „[[Prototyp]]“-Attribute, Funktionsobjekte haben „Prototyp“-Attribute und Prototypobjekte haben „Konstruktor“-Attribute.

Um den Prototyp und die mit dem Prototyp verbundenen Attributbeziehungen zu verstehen, wurde dieser Artikel geschrieben.

Ich glaube, dass Sie den Prototyp durch diesen Artikel klar verstehen und jetzt mit der Prototypenreise beginnen können.

Prototypen verstehen

Bevor wir mit der Einführung von Prototypen beginnen, wollen wir zunächst verstehen, was ein Prototyp ist.

In JavaScript ist der Prototyp auch ein Objekt. Die Attributvererbung des Objekts kann über den Prototyp realisiert werden. JavaScript-Objekte enthalten alle ein internes Attribut „[[Prototyp]“. Dieses Attribut Das entsprechende ist der Prototyp des Objekts.

„[[Prototyp]]“ ist eine interne Eigenschaft des Objekts und kann nicht direkt aufgerufen werden. Um den Prototyp eines Objekts bequem anzuzeigen, stellen Firefox und Chrome den nicht standardmäßigen (nicht von allen Browsern unterstützten) Accessor „__proto__“ bereit (ECMA hat den standardmäßigen Objektprototyp-Accessor „Object. getPrototype( Objekt)").

Beispielanalyse

Sehen wir uns prototypbezogene Konzepte anhand eines Beispiels an:

function Person(name, age){
    this.name = name;
    this.age = age;

    this.getInfo = function(){
        console.log(this.name + " is " + this.age + " years old");
    };
}

var will = new Person("Will", 28);
Nach dem Login kopieren

Im obigen Code wird ein Testament über das Person-Konstruktorobjekt erstellt . Lassen Sie uns das Willensobjekt verwenden, um den Prototyp Schritt für Schritt zu verstehen.

Schritt 1: Zeigen Sie den Prototyp des Objektwillens an

Mit dem folgenden Code können Sie den Prototyp des Objektwillens anzeigen:

console.log(will.__proto__);
console.log(will.constructor);
Nach dem Login kopieren

Ergebnisanalyse:

  • Das Objekt „Person {}“ ist der Prototyp des Objekts. Sie können sehen, dass „Person {}“ ein Prototyp ist, indem Sie es in Chrome erweitern Das Objekt verfügt außerdem über das Attribut „__proto__“ (entsprechend dem Prototyp des Prototyps).

  • In diesem Code wird auch das Attribut „Konstruktor“ verwendet. Im Prototypobjekt von JavaScript enthält es auch ein „Konstruktor“-Attribut, das dem Konstruktor entspricht, der alle Instanzen erstellt, die auf den Prototyp verweisen.

    • Durch das „Konstruktor“-Attribut können wir bestimmen, ob ein Objekt ein Array-Typ ist

      function isArray(myArray) {
          return myArray.constructor.toString().indexOf("Array") > -1;
      }
      Nach dem Login kopieren
    • Hier Das Willensobjekt selbst verfügt nicht über das Attribut „Konstruktor“ , aber durch die Suche nach Prototypen wurde das Attribut „Konstruktor“ des Willensprototyps (will.__proto__) gefunden und die Personenfunktion erhalten.

Schritt 2: Sehen Sie sich den Prototyp des Objektwillens an (will.__proto__)

Da der Prototyp des Willens „Person {}“ auch ein Objekt ist, können wir auch den Prototyp des „Willensprototyps (will.__proto__)“ überprüfen.

Führen Sie den folgenden Code aus:

console.log(will.__proto__ === Person.prototype);
console.log(Person.prototype.__proto__);
console.log(Person.prototype.constructor);
console.log(Person.prototype.constructor === Person);
Nach dem Login kopieren

Ergebnisanalyse:

  • Schauen Sie sich zunächst „will.__proto__ === Person.prototype“ an. In JavaScript verfügt jede Funktion über ein Prototypattribut. Wenn eine Funktion als Konstruktor zum Erstellen einer Instanz verwendet wird, wird der Prototypattributwert der Funktion allen Objektinstanzen als Prototyp zugewiesen (d. h. der Wert der Instanz wird festgelegt). _ _proto__-Attribut), das heißt, die Prototypen aller Instanzen beziehen sich auf das Prototyp-Attribut der Funktion. Nachdem Sie das Prototypattribut des Konstruktors verstanden haben, werden Sie definitiv verstehen, warum der erste Satz wahr ist.

    • Das Prototyp-Attribut gilt nur für Funktionsobjekte. Wenn es sich nicht um ein Funktionsobjekt handelt, gibt es kein solches Attribut.

  • Wenn Sie den Prototyp des Willensobjektprototyps über die Anweisung „Person.prototype.__proto__“ erhalten, erhalten Sie das Objekt „Object {}“, und das wird auch der Fall sein Alle Objekte später anzeigen Der Prototyp wird auf das Objekt „Object {}“ zurückgeführt.

  • Für den „Konstruktor“ des Prototypobjekts „Person.prototype“ entspricht es gemäß der vorherigen Einführung der Person-Funktion selbst.

Wie Sie oben sehen können, verweisen das Objekt „Person.prototype“ und das Funktionsobjekt „Person“ über die Attribute „constructor“ und „prototype“ aufeinander (wie (siehe Abbildung später) Diese gegenseitige Referenzbeziehung) .

Schritt 3: Sehen Sie sich den Prototyp des Objektobjekts an

Wie Sie im vorherigen Teil sehen können, ist der Prototyp des Willens Prototyp ist das Objekt „Object {}“. Tatsächlich wird in JavaScript der Prototyp aller Objekte auf das Objekt „Object {}“ zurückgeführt.

Sehen Sie sich das Objekt „Object {}“ durch einen Code an:

console.log(Person.prototype.__proto__ === Object.prototype);
console.log(typeof Object);
console.log(Object);
console.log(Object.prototype);
console.log(Object.prototype.__proto__);
console.log(Object.prototype.constructor);
Nach dem Login kopieren

Sie können es durch den folgenden Code sehen:

  • Objektobjekt Selbst ist ein Funktionsobjekt.

  • Da es sich um eine Objektfunktion handelt, muss sie über ein Prototypattribut verfügen, sodass Sie sehen können, dass der Wert von „Object.prototype“ das Prototypobjekt „Object {}“ ist.

  • Wenn Sie wiederum auf die „constructor“-Eigenschaft des „Object.prototype“-Objekts zugreifen, erhalten Sie die Object-Funktion.

  • 另外,当通过”Object.prototype.__proto__”获取Object原型的原型的时候,将会得到”null”,也就是说”Object {}”原型对象就是原型链的终点了。

Step 4: 查看对象Function的原型

在上面的例子中,Person是一个构造函数,在JavaScript中函数也是对象,所以,我们也可以通过”__proto__”属性来查找Person函数对象的原型。

console.log(Person.__proto__ === Function.prototype);
console.log(Person.constructor === Function)
console.log(typeof Function);
console.log(Function);
console.log(Function.prototype);
console.log(Function.prototype.__proto__);
console.log(Function.prototype.constructor);
Nach dem Login kopieren

结果分析 :

  • 在JavaScript中有个Function对象(类似Object),这个对象本身是个函数;所有的函数(包括Function,Object)的原型(__proto__)都是”Function.prototype”。

  • Function对象作为一个函数,就会有prototype属性,该属性将对应”function () {}”对象。

  • Function对象作为一个对象,就有”__proto__”属性,该属性对应”Function.prototype”,也就是说,”Function.__proto__ === Function.prototype”

  • 对于Function的原型对象”Function.prototype”,该原型对象的”__proto__”属性将对应”Object {}”

对比prototype和__proto__

对于”prototype”和”__proto__”这两个属性有的时候可能会弄混,”Person.prototype”和”Person.__proto__”是完全不同的。

在这里对”prototype”和”__proto__”进行简单的介绍:

  • 对于所有的对象,都有__proto__属性,这个属性对应该对象的原型

  • 对于函数对象,除了__proto__属性之外,还有prototype属性,当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的__proto__属性)

图解实例

通过上面结合实例的分析,相信你一定了解了原型中的很多内容。

但是现在肯定对上面例子中的关系感觉很凌乱,一会儿原型,一会儿原型的原型,还有Function,Object,constructor,prototype等等关系。

现在就对上面的例子中分析得到的结果/关系进行图解,相信这张图可以让你豁然开朗。

对于上图的总结如下:

  • 所有的对象都有”__proto__”属性,该属性对应该对象的原型

  • 所有的函数对象都有”prototype”属性,该属性的值会被赋值给该函数创建的对象的”__proto__”属性

  • 所有的原型对象都有”constructor”属性,该属性对应创建所有指向该原型的实例的构造函数

  • 函数对象和原型对象通过”prototype”和”constructor”属性进行相互关联

通过原型改进例子

在上面例子中,”getInfo”方法是构造函数Person的一个成员,当通过Person构造两个实例的时候,每个实例都会包含一个”getInfo”方法。

var will = new Person("Will", 28);
var wilber = new Person("Wilber", 27);
Nach dem Login kopieren

前面了解到,原型就是为了方便实现属性的继承,所以可以将”getInfo”方法当作Person原型(Person.__proto__)的一个属性,这样所有的实例都可以通过原型继承的方式来使用”getInfo”这个方法了。

所以对例子进行如下修改:

function Person(name, age){
    this.name = name;
    this.age = age;
}

Person.prototype.getInfo = function(){
    console.log(this.name + " is " + this.age + " years old");
};
Nach dem Login kopieren

修改后的结果为:

原型链

因为每个对象和原型都有原型,对象的原型指向对象的父,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。

在”理解JavaScript的作用域链“一文中,已经介绍了标识符和属性通过作用域链和原型链的查找。

这里就继续看一下基于原型链的属性查找。

属性查找

当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部(也就是 “Object.prototype”), 如果仍然没有找到指定的属性,就会返回 undefined。

看一个例子:

function Person(name, age){
    this.name = name;
    this.age = age;
}

Person.prototype.MaxNumber = 9999;
Person.__proto__.MinNumber = -9999;

var will = new Person("Will", 28);

console.log(will.MaxNumber);
// 9999
console.log(will.MinNumber);
// undefined
Nach dem Login kopieren

在这个例子中分别给”Person.prototype “和” Person.__proto__”这两个原型对象添加了”MaxNumber “和”MinNumber”属性,这里就需要弄清”prototype”和”__proto__”的区别了。

“Person.prototype “对应的就是Person构造出来所有实例的原型,也就是说”Person.prototype “属于这些实例原型链的一部分,所以当这些实例进行属性查找时候,就会引用到”Person.prototype “中的属性。

属性隐藏

当通过原型链查找一个属性的时候,首先查找的是对象本身的属性,如果找不到才会继续按照原型链进行查找。

这样一来,如果想要覆盖原型链上的一些属性,我们就可以直接在对象中引入这些属性,达到属性隐藏的效果。

看一个简单的例子:

function Person(name, age){
    this.name = name;
    this.age = age;
}

Person.prototype.getInfo = function(){
    console.log(this.name + " is " + this.age + " years old");
};

var will = new Person("Will", 28);
will.getInfo = function(){
    console.log("getInfo method from will instead of prototype");
};

will.getInfo();
// getInfo method from will instead of prototype
Nach dem Login kopieren

对象创建方式影响原型链

会到本文开始的例子,will对象通过Person构造函数创建,所以will的原型(will.__proto__)就是”Person.prototype”。

同样,我们可以通过下面的方式创建一个对象:

var July = {
    name: "July",
    age: 28,
    getInfo: function(){
        console.log(this.name + " is " + this.age + " years old");
    },
}

console.log(July.getInfo());
Nach dem Login kopieren

当使用这种方式创建一个对象的时候,原型链就变成下图了,July对象的原型是”Object.prototype”也就是说对象的构建方式会影响原型链的形式。

hasOwnProperty

“hasOwnProperty”是”Object.prototype”的一个方法,该方法能判断一个对象是否包含自定义属性而不是原型链上的属性,因为”hasOwnProperty” 是 JavaScript 中唯一一个处理属性但是不查找原型链的函数。

相信你还记得文章最开始的例子中,通过will我们可以访问”constructor”这个属性,并得到will的构造函数Person。这里结合”hasOwnProperty”这个函数就可以看到,will对象并没有”constructor”这个属性。

从下面的输出可以看到,”constructor”是will的原型(will.__proto__)的属性,但是通过原型链的查找,will对象可以发现并使用”constructor”属性。

“hasOwnProperty”还有一个重要的使用场景,就是用来遍历对象的属性。

function Person(name, age){
    this.name = name;
    this.age = age;
}

Person.prototype.getInfo = function(){
    console.log(this.name + " is " + this.age + " years old");
};

var will = new Person("Will", 28);

for(var attr in will){
    console.log(attr);
}
// name
// age
// getInfo

for(var attr in will){
    if(will.hasOwnProperty(attr)){
        console.log(attr);
    }
}
// name
// age
Nach dem Login kopieren

总结

本文介绍了JavaScript中原型相关的概念,对于原型可以归纳出下面一些点:

  • 所有的对象都有”[[prototype]]”属性(通过__proto__访问),该属性对应对象的原型

  • 所有的函数对象都有”prototype”属性,该属性的值会被赋值给该函数创建的对象的”__proto__”属性

  • 所有的原型对象都有”constructor”属性,该属性对应创建所有指向该原型的实例的构造函数

  • 函数对象和原型对象通过”prototype”和”constructor”属性进行相互关联

还有要强调的是文章开始的例子,以及通过例子得到的一张”普通对象”,”函数对象”和”原型对象”之间的关系图,当你对原型的关系迷惑的时候,就想想这张图(或者重画一张当前对象的关系图),就可以理清这里面的复杂关系了。

通过这些介绍,相信一定可以对原型有个清晰的认识。

Das obige ist der detaillierte Inhalt vonVertiefendes Verständnis der Codebeispiele für JavaScript-Prototypkonzepte (Bild). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
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
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!