阐述JS中原型链及prototype和__proto__的区别

在开始先给出我在知乎上看到的一张图,可以帮助理解:

如果现在你还不能很好的理解这副图的意思,那请继续往下看。
一、prototype和 _proto_ 的概念
prototype是函数的一个属性(每个函数都有一个prototype属性),这个属性是一个指针,指向一个对象。它是显示修改对象的原型的属性。
_ proto_ 是一个对象拥有的内置属性(请注意:prototype是函数的内置属性,_ proto_ 是对象的内置属性),_ proto_ 是JS内部使用寻找原型链的属性。简单来说,在 javascript 中每个对象都会有一个 _ proto _ 属性,当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去 _ proto _ 里找这个属性,这个 _ proto _ 又会有自己的 _ proto _,于是就这样一直找下去,也就是我们平时所说的原型链的概念.
用chrome和FF都可以访问到对象的_ proto _属性,IE不可以。
二、new 的过程

1 var Person = function(){};
2 var p = new Person();
3 
4 //*new的过程拆分成以下三步:*
5 //(1) var p={}; 也就是说,初始化一个对象p;
6 //(2) p. __ proto __ = Person.prototype;
7 //(3) Person.call(p); 也就是说构造p,也可以称之为初始化p

关键在于第二步,我们来证明一下

1 var Person = function(){};
2 var p = new Person();
3 alert(p.__proto__ === Person.prototype);

这段代码会返回true。说明我们步骤2是正确的。

三、示例

1 var Person = function(){};
2 Person.prototype.sayName = function() {
3     alert("My Name is Jacky");
4 };
5 
6 Person.prototype.age = 27;
7 var p = new Person();
8 p.sayName();

p是一个引用指向Person的对象。我们在Person的原型上定义了一个sayName方法和age属性,当我们执行p.sayName( )时,会先在this的内部查找(也就是构造函数内部),如果没有找到然后再沿着原型链向上追溯。
这里的向上追溯是怎么向上的呢?这里就要使用_ proto _属性来链接到原型(也就是Person.prototype)进行查找。最终在原型上找到了age属性。
接下来,让我们看个更复杂的代码。

 1 var Person = function() {};
 2 Person.prototype.say = function() {
 3     console.log("Person say");
 4 }
 5 Person.prototype.salary = 50000;
 6 
 7 var Programmer = function() {};
 8 Programmer.prototype = new Person();
 9 Programmer.prototype.writeCode = function() {
10     console.log("Programmer writes code");
11 };
12 Programmer.prototype.salary = 500;
13 
14 var p = new Programmer();
15 p.say();    // Person say
16 p.writeCode();  // Programmer writes code
17 console.log(p.salary); // 500
18 
19 // 推导过程一 --> 
20 // Programmer.prototype = {};
21 // Programmer.prototype.__proto__ = Person.prototype;
22 // Person.call(Programmer.prototype);
23 // 推导过程二 --> 
24 // var p = {};
25 // p.__proto__ = Programmer.prototype;
26 // p.__proto__ = new Person();
27 // p.__proto__.__proto__ = Pserson.prototype;
28 // Person.call(p.__proto__);
29 // Programmer.call(p);

当我们调用 p.say() 时,p 中是没有 say 属性,于是到 p 的 _ proto _ 属性中去找,也就是 Programmer.prototype,此时 Programmer.prototype 是等于 new Person(),但 new Person() 中也没有 say 属性,于是又到 new Person()._ proto _ 中找,此时 new Person()._ proto _ 等于 Pserson.prototype 的,我们定义了 Person.prototype.say=function(){}; 所以,p 在 Person.prototype 中就找到了这个方法。
过程:

1 p –> 
2 p.__proto__ === Programmer.prototype === new Person() –> 
3 p.__proto__.__proto__ === Programmer.prototype.__proto__ === new Person().__proto__ === Pserson.prototype

猜你喜欢

转载自www.cnblogs.com/zlq92/p/10178286.html