原型链

一、写在最前面 刚学原型链总被搞蒙,什么__proto__,prototype,有点乱。自己画了图便于自己理解记忆。
二、原型链例子 刚开始学习数组时,知道数组有许多自带的方法,学了原型链之后发现原来是通过原型链来继承这些方法的。
首先记住,被构造的实例有__proto__属性,构造它的函数有prototype属性。
1、例子a 看下面的简单代码:

function People (name){ this.name = name; } People.prototype.walk = function(){ console.log(this.name + ' is walking'); } var p1 = new People('大田田1'); var p2 = new People('大田田2');

代码解释:
(1)People是自定义的构造函数,定义了对象的“name”属性,并把这个属性赋给了this对象。
(2)在People的prototype上添加了walk方法,输出this.name is walking
(3)创建两个新实例p1和p2,给它们的“name”属性赋值。
结果分析:
p1和p2作为People的两个实例,在创建时只赋了name属性值,并没有添加walk方法,但是p1.walk()和p2.walk()都能正确输出。原因是给People.prototype上添加了walk方法。
这就涉及到下面这张原型图了。

原型链
文章图片
原型图-jianshu.png 开头说到,被构造的实例有__proto__属性,构造它的函数有prototype属性。
(1)左上角的People是自定义构造函数,里面有name,prototype。
(2)右上角是People的原型对象,里面有prototype,constructor,__proto__。
(3)下面两个框p1和p2是两个实例,有name的属性及值和__proto__。
它们之间的关系如下:
People的prototype指向原型对象的prototype,原型对象的constructor指向People。实例的__proto__指向原型对象的prototype。
用公式表示就是:p1.__proto__==People.prototype
所以,当调用p1.walk()方法时,会在p1本身里面找改方法,找不到的话就往上去原型的prototype方法中找,即在People.prototype中找。而本例子中给People.prototype添加了walk方法。因此p1和p2作为People的实例,都可以调用walk方法。
2、例子b 理解了上面的代码之后,看以下Array这个原生构造函数的例子。
arr1 = new Array(1,2,34,5)

arr1=[1,2,34,5]。Array是原生构造函数。arr1作为一个数组,具有很多方法,如下图。这些方法都是继承而来的。

原型链
文章图片
屏幕快照 2018-01-27 15.34.25.png arr1.__proto__如下图,因为arr1由Array构造的,所以constructor是Array。

原型链
文章图片
屏幕快照 2018-01-27 15.34.49.png 可以看见最后一行还有一个__proto__。嗯?什么情况,点开看看,arr1.__proto__.__proto__如下图,constructor是Object。这是因为Array.prototype是一个原型对象,所以它也是对象Object的一个实例。

原型链
文章图片
屏幕快照 2018-01-27 15.35.03.png 这里就可以做一个公式推导了。
1)arr1是Array的一个实例,所以arr1.__proto__==Array.prototype
2)由于Array.prototype是一个原型对象,所以它也是Object的一个实例,所以Array.prototype.__proto__==Object.prototype。
3)所以arr1.__proto__.__proto__==Object.prototype。
由上面几个图可以看到,数组的toString方法就是在arr1.__proto__.__proto__上的。
三、最后三句话 1、构造函数的prototype==被创建实例的__proto__
2、一切函数都由Function创建
3、一切函数的原型对象都由Object创建
【原型链】这三句话可以解释很多很多例子。

    推荐阅读