Heim > Web-Frontend > js-Tutorial > Umfassende Analyse von Prototypen in JavaScript

Umfassende Analyse von Prototypen in JavaScript

亚连
Freigeben: 2018-05-21 14:53:47
Original
1423 Leute haben es durchsucht

Dieser Artikel stellt hauptsächlich die vollständige Analyse des Prototyps in JavaScript vor. Der Prototyp ist eine wichtige Unterstützung für das Argument „Alles ist ein Objekt“ und erklärt das __proto__-Attribut und andere trockene Informationen Ich brauche es und kann darauf verweisen Objekt Kommt von, das heißt, der Endpunkt der Prototypenkette aller Dinge zeigt auf Object.prototype

  // ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", 
   // "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__",
   // "__lookupSetter__"]
   console.log(Object.getOwnPropertyNames(Object.prototype));
Nach dem Login kopieren

3. Die subtile Beziehung zwischen Konstruktoren und Instanzen (Objekten) in JS
Der Konstruktor stimmt zu Definieren Sie seine Instanz durch Prototypspezifikationen und verwenden Sie dann neue, um Instanzen zu erstellen. Ihre Rolle besteht darin, Objekte zu erzeugen.

Und der Konstruktor (Methode) selbst ist eine Instanz der Methode (Funktion), sodass ihr __proto__ (Prototypkette) dies kann auch zu finden

Objekt / Funktion F() {} Dies ist der Konstruktor, einer wird von der nativen JS-API bereitgestellt und der andere wird angepasst

neues Objekt() / neues F() {} So sieht es aus: Instanzen
Instanzen können „nur“ __proto__ überprüfen, um zu wissen, auf welchem ​​Prototyp sie basieren,
und „können“ den Prototyp der Instanz „nicht“ neu definieren, um eine Instanz der Instanz zu erstellen

Üben bringt wahres Wissen, nur wenn du dich selbst beobachtest/denkst, kannst du wirklich verstehen:

  // 先来看看构造函数到底是什么
  // function Empty() {}  function Empty() {}
  console.log(Function.prototype, Function.__proto__);
  // Object {}          function Empty() {}
  console.log(Object.prototype, Object.__proto__);
  function F() {}
  // F {}              function Empty() {}
  console.log(F.prototype, F.__proto__);
Nach dem Login kopieren

Dir wird vielleicht schwindlig, lass es uns aufschlüsseln.

Prototyp

Das Format der Prototypenausgabe ist: Konstruktorfunktionsname Prototyp

Schauen wir uns zunächst an, was Object.prototype ausgibt?

Object {} -> vorheriges Objekt ist ein Konstruktor Der Name der Funktion, der darauffolgende stellt den Prototyp dar, hier ist ein {}, also eine Instanz eines Objektobjekts (leeres Objekt)

Dann verstehen wir, was F {} bedeutet, F ist der Name des Konstruktors und der Prototyp ist auch ein leeres Objekt

  // 再来看看由构造函数构造出来的实例
  var o = new Object(); // var o = {};
  // undefined       Object {}
  console.log(o.prototype, o.__proto__);
  function F() {}
  var i = new F();
  // undefined       F {}
  console.log(i.prototype, i.__proto__);
Nach dem Login kopieren
Gehen wir etwas tiefer und definieren den Prototyp von F, um zu sehen, was passiert?
  function F() {}
  F.prototype.a = function() {};
  var i = new F();
  // undefined       F {a: function}
  console.log(i.prototype, i.__proto__);
Nach dem Login kopieren

Auf diese Weise haben wir Es ist deutlich zu erkennen, dass i aus F konstruiert ist. Der Prototyp ist {a: function}, was bedeutet, dass der ursprüngliche leere Objektprototyp eine neue a-Methode hat

Ändern wir die Situation noch einmal, was passiert, wenn wir vollständig sind den Prototyp von F abdecken?

function F() {}
  F.prototype = {
    a: function() {}
  };
  var i = new F();
  // undefined       Object {a: function}
  console.log(i.prototype, i.__proto__);
Nach dem Login kopieren

Huh~ Warum zeigt es, dass ich aus Objekt Nein erstellt wurde?

Weil wir den Prototyp von F vollständig überschreiben, was eigentlich bedeutet, dass der Prototyp als Objekt { angegeben wird? a: function}, aber dies führt dazu, dass die ursprünglichen Konstruktorinformationen verloren gehen und zum Konstruktor werden, der durch das Objekt {a: function} angegeben wird.

Was ist also der Konstruktor des Objekts {a: function}?
Weil Objekt {a: function} ist eigentlich relativ zu

var o = {a: function() {}} // new了一个Object
Nach dem Login kopieren

Dann ist der Konstruktor von o natürlich Object

Korrigieren wir diesen Fehler

  function F() {}
  F.prototype = {
    a: function() {}
  }
  // 重新指定正确的构造函数
  F.prototype.constructor = F;
  var i = new F();
  // undefined       F {a: function, constructor: function}
  console.log(i.prototype, i.__proto__);
Nach dem Login kopieren

Jetzt können wir die richtigen Prototypinformationen erhalten noch einmal~

Prototypenkette

Dann schauen wir uns an, was die Prototypenkette ist?

Einfach ausgedrückt ist sie dasselbe wie die Vererbungsbeziehung (Kette). ) in OOP. Sie gehen Schicht für Schicht nach oben, bis zum endgültigen Object.prototype


Das Wichtigste ist, herauszufinden, welche Dinge in JS (Instanz-)Objekte sind . Das ist einfach. Alles in JS ist Objekt!

Eine andere Sache, die man verstehen muss, ist, dass jedes Objekt einen Prototyp hat!

2016510172352211.jpg (560×248)Dann lasst es uns beweisen:

  Object // 这是一个函数, 函数是 Function 的实例对象, 那么就是由 Function 构造出来的
  Object.__proto__ == Function.prototype // 那么Object的原型, true
  // 这个是一个普通对象了, 因此属于 Object 的实例
  Function.prototype.__proto__ == Object.prototype // true
  // 这已经是原型链的最顶层了, 因此最终的指向 null
  Object.prototype.__proto__ == null // true

  Function // 这也是一个函数, 没错吧!
  Function.__proto__ == Function.prototype // true
  
  function A() {} // 这是一个自定义的函数, 终归还是一个函数, 没错吧! 
  A.__proto__ == Function.prototype // 任何函数都是 Function 的实例, 因此A的原型是?
  var a = new A()
  a.__proto__ == A.prototype // 实例a是由A构造函数构造出来的, 因此a的原型是由A的prototype属性定义的
  A.prototype.__proto__ == Object.prototype // 普通对象都是 Object 的示例
Nach dem Login kopieren

Prototyp und __proto__

Jedes Objekt enthält ein __proto__, das auf den „Prototyp“ dieses Objekts verweist.
Eine ähnliche Sache ist, dass jede Funktion einen Prototyp enthält. Was macht dieses Prototypobjekt?

Sehen wir uns den folgenden Code an und verwenden den Konstruktor zum Erstellen eines Objekts (oben dient das Erstellen eines Objekts in Form eines Literals).

function Foo(){};
var foo = new Foo();
console.log(foo.__proto__);
Nach dem Login kopieren
Denken Sie mal darüber nach: Worauf weist das __proto__ dieses foo-Objekts hin?

Ein Objekt, das eine Konstruktoreigenschaft enthält? Es macht nichts, wenn Sie es nicht gut verstehen. Drucken Sie einfach das Prototypattribut der Funktion Foo aus und vergleichen Sie es.

function Foo(){};
var foo = new Foo();
console.log(foo.__proto__);
console.log(Foo.prototype);
console.log(foo.__proto__ === Foo.prototype);
Nach dem Login kopieren

2016510172448163.png (163×68)

Es stellt sich heraus, dass der __proto__ des neuen Objekts foo nur auf den Prototyp der Funktion Foo zeigt.

foo.__proto__ --> Foo.prototype
Nach dem Login kopieren
Nach dem Login kopieren

Was bringt es, JS so zu entwerfen? Erinnern Sie sich an das oben Gesagte: In der Welt von JS werden Objekte nicht auf der Grundlage von Klassen (Formen) erstellt, sondern von Prototypen (einem anderen Objekt) abgeleitet. 2016510172512274.png (183×69)

Wenn wir die neue Operation ausführen, um ein neues Objekt zu erstellen, werden wir nicht auf die spezifische Implementierung der neuen Operation eingehen, aber wir sind uns sicher, dass der __proto__ des neuen Objekts auf einen Prototyp verweist Objekt.

Nur ​​dieser Code

function Foo(){};
var foo = new Foo();
Nach dem Login kopieren

foo.__proto__到底要指向谁了?你怎么不能指向Foo这个函数本身吧,虽然函数也是对象,这个有机会会详细讲。但如何foo.__proto__指向Foo固然不合适,因为Foo是一个函数,有很多逻辑代码,foo作为一个对象,继承逻辑处理没有任何意义,它要继承的是“原型对象”的属性。

所以,每个函数会自动生成一个prototype对象,由这个函数new出来的对象的__proto__就指向这个函数的prototype。

foo.__proto__ --> Foo.prototype
Nach dem Login kopieren
Nach dem Login kopieren

总结说了这么多,感觉还是没完全说清楚,不如上一张图。我曾经参考过其他网友的图,但总觉得哪里没说清楚,所以我自己画了一张图,如果觉得我的不错,请点个赞!(老子可是费了牛劲才画出来)。

2016510172555695.png (800×600)

咱们就着这张图,记住如下几个事实:

1. 每个对象中都有一个_proto_属性。

JS世界中没有类(模具)的概念,对象是从另一个对象(原型)衍生出来的,所以每个对象中会有一个_proto_属性指向它的原型对象。(参考左上角的那个用字面量形式定义的对象obj,它在内存中开辟了一个空间存放对象自身的属性,同时生成一个_proto_指向它的原型——顶层原型对象。)

2. 每个函数都有一个prototype属性。

“构造函数”为何叫构造函数,因为它要构造对象。那么根据上面第一条事实,构造出来的新对象的_proto_属性指向谁了?总不能指向构造函数自身,虽然它也是个对象,但你不希望新对象继承函数的属性与方法吧。所以,在每个构造函数都会有一个prototype属性,指向一个对象作为这个构造函数构造出来的新对象的原型。

3. 函数也是对象。

每个函数都有一些通用的属性和方法,比如apply()/call()等。但这些通用的方法是如何继承的呢?函数又是怎么创建出来的呢?试想想,一切皆对象,包括函数也是对象,而且是通过构造函数构造出来的对象。那么根据上面第二条事实,每个函数也会有_proto_指向它的构造函数的prototype。而这个构造函数的函数就是Function,JS中的所有函数都是由Function构造出来的。函数的通用属性与方法就存放在Function.prototype这个原型对象上。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

全面分析JavaScript面向对象概念中的Object类型与作用域(附有示例)

在javascript中创建对象的各种模式解析(图文教程)

详细解读JavaScript设计模式开发中的桥接模式(高级篇)

Das obige ist der detaillierte Inhalt vonUmfassende Analyse von Prototypen in JavaScript. 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