Heim > Web-Frontend > js-Tutorial > Eine einfache und grobe Erklärung des grafischen Codes der JavaScript-Prototypkette

Eine einfache und grobe Erklärung des grafischen Codes der JavaScript-Prototypkette

黄舟
Freigeben: 2017-03-08 14:10:47
Original
1226 Leute haben es durchsucht

Die Prototypenkette ist etwas verwirrend und es gibt viele Informationen im Internet. Jedes Mal, wenn ich nachts nicht schlafen kann, suche ich immer gerne nach Artikeln zum Prototyp Kette und Verschlüsse im Internet Die Wirkung ist hervorragend.

Lassen Sie sich nicht auf diesen Haufen Terminologie ein, es wird Ihnen wirklich nichts weiterbringen, als Ihren Verstand zu verdrehen. Schauen wir uns die Prototypenkette einfach und grob an und denken wir an Dinge, die nichts mit Code zu tun haben, wie Menschen, Monster und Transen.

1) Menschen werden aus Menschen geboren, Dämonen werden aus Dämonen geboren. Sowohl Menschen als auch Dämonen sind Objektinstanzen, und Menschen und Dämonen sind Prototypen. Prototypen sind auch Objekte, sogenannte Prototypobjekte.

2) Wenn eine menschliche Mutter Sex mit einem menschlichen Vater hat, werden viele menschliche Babys geboren. Wenn eine Dämonenmutter Sex mit einem Dämonenvater hat, werden viele geboren Wenn Dämonenbabys geboren werden, ist PaPaPaPa die Konstrukteursfunktion, die allgemein als Menschenerschaffung bezeichnet wird.

3) Menschen zeichnen die Informationen über Sex auf, sodass Sie die Informationen über Sex über Menschen finden können, was bedeutet, dass Sie die Struktur über die Prototypobjektfunktion finden können.

4) Menschen können viele Babys zur Welt bringen, aber diese Babys haben nur eine Mutter. Das ist die Einzigartigkeit des Prototyps.

5) Menschen werden auch aus Menschen geboren, und durch Menschen können wir andere Menschen finden. Diese Beziehung wird als Prototypenkette bezeichnet.

6) Die Prototypenkette ist nicht unendlich. Wenn man immer wieder nach oben schaut, wird man schließlich feststellen, dass die Leute verdammte... Sie sind verdammt noch mal keine Menschen Das heißt, die Prototypenkette zeigt letztendlich auf Null.

7) Die von einem Menschen geborene Person wird wie ein Mensch aussehen, und das von einem Monster geborene Monster wird hässlich wie ein Monster sein. Dies nennt man Vererbung.

8) Du hast die Hautfarbe deiner Mutter geerbt, deine Mutter hat die verdammte Hautfarbe deiner Mutter geerbt, die verdammte Hautfarbe deiner Mutter …, das ist das Erbe der Prototypenkette.

9) Wenn Sie kein Zuhause haben, dann bezieht sich Ihr Zuhause auf das Zuhause Ihrer Mutter; wenn Ihre Mutter kein Zuhause hat, dann bezieht sich Ihr Zuhause auf das Zuhause Ihrer Mutter... Dies ist die Aufwärtssuche der Prototypenkette.

10) Sie werden das Aussehen Ihrer Mutter erben, aber Sie können Ihre Haare auch färben, waschen, schneiden und föhnen, was bedeutet, dass die Eigenschaften des Objekts angepasst werden können und die geerbten Eigenschaften überschreiben.

11) Obwohl Sie Ihre Haare gewaschen, geschnitten und gelb gefärbt haben, können Sie das Aussehen Ihrer Mutter nicht ändern. Die jüngeren Brüder und Schwestern, die von Ihrer Mutter geboren wurden wird dasselbe sein wie Ihr gelbes Haar. Es spielt keine Rolle, ob Sie schneiden oder blasen, es bedeutet, dass die Objektinstanz die Eigenschaften des Prototyps nicht ändern kann.

12) Aber wenn Ihr Haus niedergebrannt wird, weil Sie mit dem Feuer spielen, bedeutet das, dass Ihr Haus, das Haus Ihrer Mutter und die Häuser Ihrer Brüder alle niedergebrannt sind. Dies ist die gemeinsame Nutzung von Prototypattributen.

13) Der Spitzname deiner Mutter ist A-Zhen, und die Tanten von nebenan nennen dich A-Zhen'er. Aber die Haare deiner Mutter haben sich von „Rejoice“ zu „Golden Retriever Lion Queen“ geändert, und die Tanten von nebenan haben ihre Haare geändert Spitzname, um dich Golden Retriever Prince zu nennen. Das ist die Dynamik von Prototypen.

14) Deine Mutter liebt Schönheit, deshalb ist sie zur Schönheitsoperation nach Korea gegangen, sodass deine Mutter sie nicht einmal wiedererkennen kann. Auch wenn sich die Haare deiner Mutter wieder in Freude verwandelt haben, ruft die Nachbarin immer noch an Du, der Golden-Retriever-Prinz. Da niemand Ihre Mutter erkannte, wurde Ihre Mutter nach einer plastischen Operation neu gestaltet. Dies ist eine völlige Neufassung des Prototyps.

Nein! Du hast genug! Nicht BB! Zeig mir den Code!

function Person (name) { this.name = name; }
function Mother () { }
Mother.prototype = {    //Mother的原型
    age: 18,
    home: ['Beijing', 'Shanghai']
};
Person.prototype = new Mother(); //Person的原型为Mother

//用chrome调试工具查看,提供了__proto__接口查看原型
var p1 = new Person('Jack'); //p1:'Jack'; __proto__:18,['Beijing','Shanghai']
var p2 = new Person('Mark'); //p2:'Mark'; __proto__:18,['Beijing','Shanghai']

p1.age = 20;  
/* 实例不能改变原型的基本值属性,正如你洗剪吹染黄毛跟你妈无关
 * 在p1实例下增加一个age属性的普通操作,与原型无关。跟var o={}; o.age=20一样。
 * p1:下面多了个属性age,而__proto__跟 Mother.prototype一样,age=18。
 * p2:只有属性name,__proto__跟 Mother.prototype一样
 */

p1.home[0] = 'Shenzhen'; 
/* 原型中引用类型属性的共享,正如你烧了你家,就是烧了你全家的家
 * 这个先过,下文再仔细唠叨一下可好?
 * p1:'Jack',20; __proto__:18,['Shenzhen','Shanghai']
 * p2:'Mark';    __proto__:18,['Shenzhen','Shanghai']
 */

p1.home = ['Hangzhou', 'Guangzhou']; 
/* 其实跟p1.age=20一样的操作。换成这个理解: var o={}; o.home=['big','house']
 * p1:'Jack',20,['Hangzhou','Guangzhou']; __proto__:18,['Shenzhen','Shanghai']
 * p2:'Mark';                             __proto__:18,['Shenzhen','Shanghai']
 */

delete p1.age;    
/* 删除实例的属性之后,原本被覆盖的原型值就重见天日了。正如你剃了光头,遗传的迷人小卷发就长出来了。
 * 这就是向上搜索机制,先搜你,然后你妈,再你妈他妈,所以你妈的改动会动态影响你。
 * p1:'Jack',['Hangzhou','Guangzhou']; __proto__:18,['Shenzhen','Shanghai']
 * p2:'Mark';                          __proto__:18,['Shenzhen','Shanghai']
 */

Person.prototype.lastName = 'Jin'; 
/* 改写原型,动态反应到实例中。正如你妈变新潮了,邻居提起你都说是潮妇的儿子
 * 注意,这里我们改写的是Person的原型,就是往Mother里加一个lastName属性,等同于Mother.lastName='Jin'
 * 这里并不是改Mother.prototype,改动不同的层次,效果往往会有很大的差异。
 * p1:'Jack',['Hangzhou','Guangzhou']; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']
 * p2:'Mark';                          __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']
 */

Person.prototype = { 
    age: 28, 
    address: { country: 'USA', city: 'Washington' }
};
var p3 = new Person('Obama'); 
/* 重写原型!这个时候Person的原型已经完全变成一个新的对象了,也就是说Person换了个妈,叫后妈。
 * 换成这样理解:var a=10; b=a; a=20; c=a。所以b不变,变得是c,所以p3跟着后妈变化,与亲妈无关。
 * p1:'Jack',['Hangzhou','Guangzhou']; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']
 * p2:'Mark';                          __proto__:'jin';__proto__:18,['Shenzhen','Shanghai']
 * p3:'Obama';__proto__: 28 {country: 'USA', city: 'Washington'}
 */

Mother.prototype.no = 9527;
/* 改写原型的原型,动态反应到实例中。正如你妈他妈变新潮了,邻居提起你都说你丫外婆真潮。
 * 注意,这里我们改写的是Mother.prototype,p1p2会变,但上面p3跟亲妈已经了无瓜葛了,不影响他。
 * p1:'Jack',['Hangzhou','Guangzhou']; __proto__:'jin';__proto__:18,['Shenzhen','Shanghai'],9527
 * p2:'Mark';                          __proto__:'jin';__proto__:18,['Shenzhen','Shanghai'],9527
 * p3:'Obama';__proto__: 28 {country: 'USA', city: 'Washington'}
 */

Mother.prototype = { 
    car: 2, 
    hobby: ['run','walk']
};
var p4 = new Person('Tony');
/* 重写原型的原型!这个时候Mother的原型已经完全变成一个新的对象了!人他妈换了个后妈!
 * 由于上面Person与Mother已经断开联系了,这时候Mother怎么变已经不影响Person了。
 * p4:'Tony';__proto__: 28 {country: 'USA', city: 'Washington'}
 */

Person.prototype = new Mother(); //再次绑定
var p5 = new Person('Luffy');
// 这个时候如果需要应用这些改动的话,那就要重新将Person的原型绑到mother上了
// p5:'Luffy';__proto__: 2, ['run','walk']

p1.__proto__.__proto__.__proto__.__proto__ //null,你说原型链的终点不是null?
Mother.__proto__.__proto__.__proto__    //null,你说原型链的终点不是null?
Nach dem Login kopieren

Können Sie es grundsätzlich verstehen, nachdem Sie es gelesen haben?

Lassen Sie uns nun über den Unterschied zwischen p1.age = 20, p1.home = ['Hangzhou', 'Guangzhou'] und p1.home[0] = 'Shenzhen' sprechen. p1.home[0] = ‚Shenzhen‘; Zusammenfassend hat es die Form p1.object.method, p1.object.property.

p1.age = 20; p1.home = ['Hangzhou', 'Guangzhou']; Vergessen Sie zuerst, wie wir das Attribut hinzufügen:

var obj = new Object();
obj.name='xxx'; 
obj.num = [100, 200];
Nach dem Login kopieren

Ist das sinnvoll? Das Gleiche.

Warum erstellt p1.home[0] = ‚Shenzhen‘ dann kein Home-Array-Attribut unter p1 und setzt dann seine erste Position auf ‚Shenzhen‘? Vergessen wir das zuerst. Denken Sie an das obj-Objekt oben, wenn es so geschrieben ist: var obj.name = ‚xxx‘, obj.num = [100, 200], können Sie das gewünschte Ergebnis erhalten? Offensichtlich erhalten Sie nichts als eine Fehlermeldung. Da obj noch nicht definiert wurde, wie können wir ihm Dinge hinzufügen? Ebenso ist home in p1.home[0] nicht unter p1 definiert, sodass home[0] nicht direkt in einem Schritt definiert werden kann. Wenn Sie ein Home-Array unter p1 erstellen möchten, würden Sie es natürlich so schreiben:

p1.home = []; 
p1.home[0] = 'Shenzhen';
Nach dem Login kopieren

Ist das nicht unsere am häufigsten verwendete Methode?

而之所以 p1.home[0] = ‘Shenzhen’ 不直接报错,是因为在原型链中有一个搜索机制。当我们输入 p1.object 的时候,原型链的搜索机制是先在实例中搜索相应的值,找不到就在原型中找,还找不到就再往上一级原型中搜索……一直到了原型链的终点,就是到null还没找到的话,就返回一个 undefined。当我们输入 p1.home[0] 的时候,也是同样的搜索机制,先搜索 p1 看有没有名为 home 的属性和方法,然后逐级向上查找。最后我们在Mother的原型里面找到了,所以修改他就相当于修改了 Mother 的原型啊。

一句话概括:p1.home[0] = ‘Shenzhen’ 等同于 Mother.prototype.home[0] = ’Shenzhen’。

由上面的分析可以知道,原型链继承的主要问题在于属性的共享,很多时候我们只想共享方法而并不想要共享属性,理想中每个实例应该有独立的属性。因此,原型继承就有了下面的两种改良方式:

1)组合继承

function Mother (age) {
    this.age = age;
    this.hobby = ['running','football']
}
Mother.prototype.showAge = function () {
    console.log(this.age); 
};

function Person (name, age) { 
    Mother.call(this, age);  //第二次执行
    this.name = name; 
}
Person.prototype = new Mother();  //第一次执行
Person.prototype.constructor = Person;
Person.prototype.showName = function () {
    console.log(this.name);
}

var p1 = new Person('Jack', 20); 
p1.hobby.push('basketball');  //p1:'Jack'; __proto__:20,['running','football']
var p2 = new Person('Mark', 18);  //p2:'Mark'; __proto__:18,['running','football']
Nach dem Login kopieren

结果是酱紫的:

这里第一次执行的时候,得到 Person.prototype.age = undefined, Person.prototype.hobby = ['running','football'],第二次执行也就是 var p1 = new Person(‘Jack’, 20) 的时候,得到 p1.age =20, p1.hobby = ['running','football'],push后就变成了 p1.hobby = ['running','football', 'basketball']。其实分辨好 this 的变化,理解起来也是比较简单的,把 this 简单替换一下就能得到这个结果了。 如果感觉理解起来比较绕的话,试着把脑子里面的概念扔掉吧,把自己当浏览器从上到下执行一遍代码,结果是不是就出来了呢?

通过第二次执行原型的构造函数 Mother(),我们在对象实例中复制了一份原型的属性,这样就做到了与原型属性的分离独立。细心的你会发现,我们第一次调用 Mother(),好像什么用都没有呢,能不调用他吗?可以,就有了下面的寄生组合式继承。

2)寄生组合式继承

function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}

function inheritPrototype(Person, Mother){
    var prototype = object(Mother.prototype); 
    prototype.constructor = Person;    
    Person.prototype = prototype;    
}

function Mother (age) {
    this.age = age;
    this.hobby = ['running','football']
}
Mother.prototype.showAge = function () {
    console.log(this.age); 
};

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

inheritPrototype(Person, Mother);

Person.prototype.showName = function () {
    console.log(this.name);
}

var p1 = new Person('Jack', 20); 
p1.hobby.push('basketball');//p1:'Jack'; __proto__:20,['running','football']
var p2 = new Person('Mark', 18); //p2:'Mark'; __proto__:18,['running','football']
Nach dem Login kopieren

结果是酱紫的:

原型中不再有 age 和 hobby 属性了,只有两个方法,正是我们想要的结果!

关键点在于 object(o) 里面,这里借用了一个临时对象来巧妙避免了调用new Mother(),然后将原型为 o 的新对象实例返回,从而完成了原型链的设置。很绕,对吧,那是因为我们不能直接设置 Person.prototype = Mother.prototype 啊。

小结

说了这么多,其实核心只有一个:属性共享和独立的控制,当你的对象实例需要独立的属性,所有做法的本质都是在对象实例里面创建属性。若不考虑太多,你大可以在Person里面直接定义你所需要独立的属性来覆盖掉原型的属性。总之,使用原型继承的时候,要对于原型中的属性要特别注意,因为他们都是牵一发而动全身的存在。

下面简单罗列下js中创建对象的各种方法,现在最常用的方法是组合模式,熟悉的同学可以跳过到文章末尾点赞了。

1)原始模式

//1.原始模式,对象字面量方式
var person = { 
    name: 'Jack',
    age: 18,
    sayName: function () { alert(this.name); }
};
//1.原始模式,Object构造函数方式
var person = new Object();
person.name = 'Jack';
person.age = 18;
person.sayName = function () {
    alert(this.name);
};
Nach dem Login kopieren

显然,当我们要创建批量的person1、person2……时,每次都要敲很多代码,资深copypaster都吃不消!然后就有了批量生产的工厂模式。

2)工厂模式

//2.工厂模式,定义一个函数创建对象
function creatPerson (name, age) {
    var temp = new Object(); 
    person.name = name;
    person.age = age;
    person.sayName = function () {
        alert(this.name);
    };
    return temp; 
}
Nach dem Login kopieren

工厂模式就是批量化生产,简单调用就可以进入造人模式(啪啪啪……)。指定姓名年龄就可以造一堆小宝宝啦,解放双手。但是由于是工厂暗箱操作的,所以你不能识别这个对象到底是什么类型、是人还是狗傻傻分不清(instanceof 测试为 Object),另外每次造人时都要创建一个独立的temp对象,代码臃肿,雅蠛蝶啊。

3)构造函数

//3.构造函数模式,为对象定义一个构造函数
function Person (name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function () {
        alert(this.name);
    };    
}
var p1 = new Person('Jack', 18); //创建一个p1对象
Person('Jack', 18);    //属性方法都给window对象,window.name='Jack',window.sayName()会输出Jack
Nach dem Login kopieren

构造函数与C++、JAVA中类的构造函数类似,易于理解,另外Person可以作为类型识别(instanceof 测试为 Person 、Object)。但是所有实例依然是独立的,不同实例的方法其实是不同的函数。这里把函数两个字忘了吧,把sayName当做一个对象就好理解了,就是说张三的 sayName 和李四的 sayName是不同的存在,但显然我们期望的是共用一个 sayName 以节省内存。

4)原型模式

//4.原型模式,直接定义prototype属性
function Person () {}
Person.prototype.name = 'Jack';
Person.prototype.age = 18;
Person.prototype.sayName = function () { alert(this.name); };
//4.原型模式,字面量定义方式
function Person () {}
Person.prototype = {
    name: 'Jack',
    age: 18,
    sayName: function () { alert(this.name); }
};
var p1 = new Person(); //name='Jack'
var p2 = new Person(); //name='Jack'
Nach dem Login kopieren

这里需要注意的是原型属性和方法的共享,即所有实例中都只是引用原型中的属性方法,任何一个地方产生的改动会引起其他实例的变化。

5)混合模式(构造+原型)

//5. 原型构造组合模式,
function Person (name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype = {
    hobby: ['running','football'];
    sayName: function () { alert(this.name); },
    sayAge: function () { alert(this.age); }
};
var p1 = new Person('Jack', 20); 
//p1:'Jack',20; __proto__: ['running','football'],sayName,sayAge
var p2 = new Person('Mark', 18); 
//p1:'Mark',18;__proto__: ['running','football'],sayName,sayAge
Nach dem Login kopieren

做法是将需要独立的属性方法放入构造函数中,而可以共享的部分则放入原型中,这样做可以最大限度节省内存而又保留对象实例的独立性。



Das obige ist der detaillierte Inhalt vonEine einfache und grobe Erklärung des grafischen Codes der JavaScript-Prototypkette. 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