每个函数都有一个prototype的属性,当我们以这个函数为构造函数创建实例时(即用new的形式),创建出来的这个对象是没有prototype的属性的。
以下代码为例:
![](https://images0.cnblogs.com/blog/542254/201307/02173545-8a7b655e84504d40945afe167f138916.png)
在console里进行调试
![](https://images0.cnblogs.com/blog/542254/201307/02173554-778d4b8e8fd547f092253cad5edd50b9.png)
cf 拥有一个prototype的属性,这个属性就叫做原型。这个原型本身是一个对象cf{},我们叫它原型对象。
cf 的原型对象有一个constructor的属性,它就是构造函数。我们可以看到,这个构造函数是cf本身。(当然它还有一些别的属性。)
cf1 作为 cf 的实例,它拥有了cf.prototype里的所有属性。把cf1展开看一下:
![](https://images0.cnblogs.com/blog/542254/201307/02173602-9d6d79f52f6f495ea2dfd77743097a1f.png)
可以看到cf1 有一个隐式属性_proto_,这个属性是无法通过ECMA语句访问到的。它指向了cf.prototype这个原型对象,这就是原性链。
原型对象本身作为ECMA内置对象Object的一个实例,它也有_proto_,指向的是Object.prototype,这就构成了一个链表的结构。
这个链表就决定了在查找属性时的顺序。例如ECMA在查找 cf1.p1时,会先查找它本身,若没有p1这个属性,再沿着_proto_找。
在这里 new 操作符所做的事情,可以分为以下:
1、建立一个新对象cf1 var cf1 = cf{ };
2、将cf1的_proto_指向原型对象 cf1._proto = cf.prototype
3、将cf1作为this的参数,调用构造函数cf。 cf.call(cf1)