Heim >Web-Frontend >js-Tutorial >Eine kurze Analyse der JavaScript-Vererbung und der Prototypenkette
Dieser Artikel vermittelt Ihnen Wissen über Vererbung und Prototypenkette in Javascript, einschließlich Fragen im Zusammenhang mit Konstruktoren, Prototypen und Klassensyntaxzucker. Ich hoffe, dass er für alle hilfreich ist.
Die Vererbung und Prototypenkette von JavaScript sind die seltenen und schwer verständlichen Teile, auf die ich beim Erlernen des Frontends gestoßen bin . Hier werde ich alles aufzeichnen, was ich weiß und gelernt habe. Ich hoffe, dass es den Brüdern, die noch damit zu kämpfen haben, ein wenig helfen kann. Ich freue mich auch über Ihre Kritik und Korrekturen.
Der Konstruktor besteht sowohl aus Instanzmitgliedern als auch aus statischen Mitgliedern, wobei Instanzmitglieder Mitglieder sind, die über das Schlüsselwort „this“ innerhalb der Funktion hinzugefügt werden Der Zugriff erfolgt über das instanziierte Objekt, nachdem das Objekt instanziiert wurde. Statische Mitglieder sind Mitglieder, die der Funktion selbst hinzugefügt wurden und nur über den Konstruktor zugänglich sind. //创造一个构造函数let Father = function(name,age){
//实例成员
this.name = name;
this.age = age;
this.method = "我是一个实例成员";}
//静态成员Father.like = "mother";
//检验实例对象是否能够被构造函数直接访问console.log(Father.method);
//undefinedconsole.log(Father.like);
//mother
//实例化一个对象let father = new Father("小王",27);
//检验静态对象是否能够被实例化对象访问console.log(father.name);
//小王console.log(father.age);
//27console.log(father.like);
//undefined
2.2 Der Prozess der Instanziierung eines Objekts
kann verwendet werden, um ein instanziiertes Objekt über den Konstruktor zu implementieren. Was passiert also während des spezifischen Instanziierungsprozesses? Es kann grob in die folgenden Schritte unterteilt werden: (1) Erstellen Sie ein leeres Objekt son {}
(2) Bereiten Sie eine Prototyp-Kettenverbindung für son son.__proto__ = Father.prototype
vor (3) Binden Sie dies erneut, sodass das This des Konstruktors auf das neue Objekt Father.call(this)
zeigt. son.__proto__ = Father.prototype
(3) 重新绑定this,使构造函数的this指向新对象 Father.call(this)
(4) 为新对象属性赋值 son.name
(5) 返回this return this
,此时的新对象就拥有了构造函数的方法和属性了
构造函数的方法分为两种,第一种为在函数内部直接定义的方法,第二种为通过原型添加的方法;
//函数内部直接定义的方法let Father = function(){ this.read = function(){ console.log("我是内部定义的read方法!"); }}//通过Eine kurze Analyse der JavaScript-Vererbung und der Prototypenkette添加的方法Father.prototype.look = function(){ console.log("我是通过Eine kurze Analyse der JavaScript-Vererbung und der Prototypenkette定义的look方法!");} //实例化对象进行检验let father1 = new Father();let father2 = new Father(); father1.read(); //我是内部定义的read方法!father2.read(); //我是内部定义的read方法!console.log(father1.read === father2.read); //falsefather1.look(); //我是通过Eine kurze Analyse der JavaScript-Vererbung und der Prototypenkette定义的look方法!father2.look(); //我是通过Eine kurze Analyse der JavaScript-Vererbung und der Prototypenkette定义的look方法!console.log(father1.look === father2.look); /true
可以发现,函数内部直接定义的方法在每实例化一个新的对象以后,都会给这个方法分配一个新的内存空间,而通过原型添加的方法便会共享一个空间。
不存在内存空间的问题,判断时看其值是否相同;
let Father = function(name){ this.name = name;}let father1 = new Father("小王"); let father2 = new Father("小红"); console.log(father1.name === father2.name); //falselet father1 = new Father("小王"); let father2 = new Father("小王"); console.log(father1.name === father2.name); //true
因此我们可以总结一下定义构造函数的基本规则,即公共属性定义到构造函数里面,公共方法我们放到原型对象身上。
Father.prototype 就是原型,它是一个对象,也可以称为原型对象。
原型的作用,就是共享方法。
我们通过 Father.prototype.method
可以共享方法,不会反应开辟空间存储方法。
原型中this的指向是实例。
Eine kurze Analyse der JavaScript-Vererbung und der Prototypenkette本人感觉是一个对于初学者或者说是部分前端菜鸡(例如本人)来说特别难以理解的东西,为了让下面的部分更容易理解,这里强行先记住以下几点:
__proto__
是每个对象都有的属性,prototype是每个函数特有的方法;__proto__
属性都会指向自身构造函数的prototype;Function.__proto__
=== Function.prototype;Object.prototype.__proto__
=== null 也就是Eine kurze Analyse der JavaScript-Vererbung und der Prototypenkette的终点;原型与原型层层相链接的过程即为Eine kurze Analyse der JavaScript-Vererbung und der Prototypenkette。
对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__
原型的存在每个对象都有__proto__
son.name Werte zu
( 5) Geben Sie dies zurück geben Sie dies zurück
Zu diesem Zeitpunkt verfügt das neue Objekt über die Methoden und Eigenschaften des Konstruktors
let Father = function(name){ this.name = name;}let father = new Father("老王");console.log(father.__proto__ === Father.prototype); //true //验证上述说法中的第二条
Man kann feststellen, dass die Methode direkt innerhalb der Funktion definiert ist Funktion ist in jedem Nach der Instanziierung eines neuen Objekts wird dieser Methode ein neuer Speicherplatz zugewiesen, und über den Prototyp hinzugefügte Methoden teilen sich denselben Speicherplatz.
function Star(name) { this.name = name; //(1)首先看obj对象身上是否有dance方法,如果有,则执行对象身上的方法 this.dance = function () { console.log(this.name + '1'); }}//(2)如果没有dance方法,就去构造函数原型对象prototype身上去查找dance这个方法。Star.prototype.dance = function () { console.log(this.name + '2');}; //(3)如果再没有dance方法,就去Object原型对象prototype身上去查找dance这个方法。Object.prototype.dance = function () { console.log(this.name + '3');}; //(4)如果再没有,则会报错。let obj = new Star('小红');obj.dance();
Wir können also die Grundregeln für die Definition von Konstruktoren zusammenfassen, d Konstruktor und öffentliche Methoden werden im Prototypobjekt platziert.
3. Prototyp
3.1 Was ist ein Prototyp? 🎜🎜Father.prototype ist ein Prototyp. Es ist ein Objekt und kann auch als Prototypobjekt bezeichnet werden. 🎜🎜3.2 Welche Rolle spielt der Prototyp? 🎜🎜Die Rolle des Prototyps besteht darin, Methoden zu teilen. 🎜🎜Wir können Methoden überFather.prototype.method
teilen, die die Speicherplatzspeichermethode nicht widerspiegeln. 🎜🎜3.3 Wohin weist dies im Prototyp hin? 🎜🎜Dies im Prototyp weist auf die Instanz hin. 🎜🎜🎜4. Prototypenkette 🎜🎜🎜 Ich bin der Meinung, dass die Prototypenkette für Anfänger oder einige Frontend-Neulinge (wie mich) besonders schwer zu verstehen ist ist ein erzwungener erster Schritt. Beachten Sie die folgenden Punkte: 🎜__proto__
ist ein Attribut jedes Objekts, Prototyp ist eine für jede Funktion einzigartige Methode __proto__
zeigt auf den Prototyp seines eigenen Konstruktors. Object.prototype.__proto__
=== null ist das Ende der Prototypenkette;__proto__
und jedes Objekt __proto__
hat 🎜function Star(name) { this.name = name;}Star.prototype = { dance:function(){ console.log("重定义prototype"); }}Star.prototype.constructor = Star;🎜4.3 Prototypenkettendiagramm🎜🎜🎜🎜🎜In Kombination mit den ersten paar Punkten sollte es kein großes Problem sein, das obige Bild zu verstehen. Der eingekreiste Teil im Bild ist die schreckliche Prototypenkette. 🎜🎜4.4 So durchsuchen Sie die Prototypenkette🎜
//定义一个父类function Father(name) { this.name = name;}Father.prototype.dance = function () { console.log('I am dancing');};//定义一个子类function Son(name, age) { Father.call(this, name); this.age = age;}//通过赋值的方法连接Son.prototype = Father.prototype;//为子类添加方法Son.prototype.sing = function () { console.log('I am singing');}; let son = new Son('小红', 100); //此时父类也被影响了console.log(Father.prototype) //{dance: ƒ, sing: ƒ, constructor: ƒ}🎜(1) Überprüfen Sie zunächst, ob es eine Tanzmethode für das Objekt obj gibt. Wenn ja, führen Sie die Methode für das Objekt aus. 🎜🎜(2) Wenn es keine Tanzmethode gibt, gehen Sie zum Konstruktor-Prototyp-Objektprototyp, um die Tanzmethode zu finden. 🎜🎜(3) Wenn es keine Tanzmethode gibt, gehen Sie zum Objektprototyp-Objektprototyp, um die Tanzmethode zu finden. 🎜🎜(4) Wenn nicht mehr vorhanden ist, wird ein Fehler gemeldet. 🎜
有两种添加方法,第一种为上面的写法,直接通过 构造函数.prototype.方法名 进行添加;第二种为重定义构造函数的prototype,但是此种情况会丢失掉原有的constructor构造器,所以一定要再连接回去,例子如下:
function Star(name) { this.name = name;}Star.prototype = { dance:function(){ console.log("重定义prototype"); }}Star.prototype.constructor = Star;
另外,类似于Array、String这些内置的类是不能这么处理的。
这里就长话短说,首先我们要明确继承需要继承哪些东西,在前文中我们提到了定义构造函数的基本规则,即**公共属性定义到构造函数里面,公共方法我们放到原型对象身上。**我们所需要继承的东西也不外乎就这二者,公共属性的继承可以通过call()或者apply()进行this的指向定义,而公共方法可以通过原型对象的赋值进行处理,因此我们很容易想到如下的方法:
//定义一个父类function Father(name) { this.name = name;}Father.prototype.dance = function () { console.log('I am dancing');};//定义一个子类function Son(name, age) { Father.call(this, name); this.age = age;}//通过赋值的方法连接Son.prototype = Father.prototype;//为子类添加方法Son.prototype.sing = function () { console.log('I am singing');}; let son = new Son('小红', 100); //此时父类也被影响了console.log(Father.prototype) //{dance: ƒ, sing: ƒ, constructor: ƒ}
很显然,当我们只想修改子类里面的方法时,显然上述方法不太合适;因此 我们可以尝试new一个新的父类出来,代码如下:
function Father(name) { this.name = name;}Father.prototype.dance = function () { console.log('I am dancing');};function Son(name, age) { Father.call(this, name); this.age = age;}Son.prototype = new Father();Son.prototype.sing = function () { console.log('I am singing');};let son = new Son('小红', 100);console.log(Father.prototype) //{dance: ƒ, constructor: ƒ}
对于以前了解过面向对象编程的程序员来讲,上述关于继承的写法属实让人有些难以接受,因此在es6里面新增了一个语法糖来更方便更便捷地书写继承,这里就直接上代码了;
class Father { constructor(name) { this.name = name; } dance() { console.log("我是" + this.name + ",我今年" + this.age + "岁," + "我在跳舞"); }}class Son extends Father { constructor(name, age) { super(name); this.age = age; } sing() { console.log("我是" + this.name + ",我今年" + this.age + "岁," + "我在唱歌"); }}let obj = new Son('小红', 19); obj.sing();obj.dance();
分析一下上面代码,首先一个类(构造函数)里面依旧为两部分,即公共属性和公共方法,constructor() 里面存放了该构造函数的公共属性,后面接着的便是公共方法,extends 关键字表示继承的是哪个类,super() 便是将里面父类里面相应的公共属性拿出来,这样看下来便可以将代码规整许多。
相关推荐:javascript学习教程
Das obige ist der detaillierte Inhalt vonEine kurze Analyse der JavaScript-Vererbung und der Prototypenkette. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!