这是一篇学习笔记。
个人心得:
关于原型和原型链这一块,很难,但是,一旦理解,就通了。
对于这一块,我之前不懂的时候,非要去弄明白,特别痛苦,之后,看到了王福朋老师的闭包原型系列,真的是茅塞顿开!看完之后,我就拿起JavaScript高程3,高程3第6章节,耐心跟着看也就明白了。之后,再去做一些图解,如果能够根据继承画出所有的关系,没有矛盾的点,那就基本没问题了。再到网上找差不多的文章看,如果没有冲突点,那这一块就没问题了。
参考的内容:
http://www.cnblogs.com/wangfupeng1988/p/4001284.html ---王福朋的闭包原型系列
你不知道的JavaScript 上
JavaScript高级程序设计 3
内容:
一些名词的解释 +几个图解(所以图片会比较多) 。
1:简单的实例
2:完整的实例
3:重写原型对象
4:原型继承
原型/继承
JavaScript中的对象都有一个内置属性 [[prototype]]属性。在表示的时候可以用__proto__表示。
__proto__ : 每个对象都有这样一个属性,指向该对象的构造函数的prototype的指向。
所有原型链的最后指向都是null。
除了Object.create(null),直接创建的对象的原型是null/没有原型,即不继承任何属;其余的对象的原型链上null之前都有一个Object.prototype原型对象。
Object的prototype对象的[[prototype]]内部属性的值是null。即:Object.prototype.__proto__ === null //true。
所有通过对象直接量创建的对象都有一个共同的原型对象:Object.prototype
通过关键字new和构造函数调用创建的对象的原型就是构造函数的prototype属性所指向的对象。
(当通过new和构造函数生成实例,实例的原型对象就会锁定)。
JavaScript中的内建函数以及用户自定义函数都是通过Function 这个函数创建的。
所有的函数默认都会拥有一个名为prototype的不可枚举的属性。这个属性指向一个对象,被称为这个函数的原型对象。
每个原型有一个不可枚举的属性constructor。这个属性引用的是对象关联的函数,即constructor属性的值是一个函数对象。
而Function是由它自己创建的,所以:
Function.__proto__ === Function.prototype ; // true;
new 调用构造函数的一个重要特征:
构造函数的prototype属性值被用做新对象的原型。即通过同一个构造函数创建的对象都继承自同一个对象。
构造函数,原型对象,实例它们都是对象!
instanceof :左边走__proto__,右边走prototype,如果能重合,返回true,否则,返回false。
A instanecof B,一般,A是一个函数,B是一个对象。
使用new的构造函数调用会生成prototype和constructor引用。
如何理解函数,对象,实例,原型,构造函数之间的关系,图解是非常好的方式,所谓有图有真相。
可以通过原型链(通过__proto__串在一起的原型形成了一条链)把它们串在一起理解。
1:
function Foo(){ /*...*/} var a1=new Foo(); var a2=new Foo();
这是一个非常简单的构造函数和实例对象。
这样,它们的关系图就出来了。
实例a1,a2,函数Fun1,原型Fun1.prototype,都是对象.。
函数Fun1有一个prototype属性,指向一个对象,名为Fun1.prototype,成为Fun1的原型对象。
原型对象Fun1.prototype 有一个constructor属性,指向该对象关联的函数。
实例a1,a2都有一个__proto__,指向该实例的构造函数的prototype的指向,并且它们指向的是同一个原型对象,因为a1,a2都是通过new和Fun1构造函数调用生成的实例。
这个图是比较基本的,并没有展现所有的关系,下一张图会进一步展现它们的关系。
2:
对象都有[[prototype]]属性,属性值为该对象构造函数的prototype值。
上面的构造函数,原型对象,实例,都是对象,所以它们都有[[prototype]]属性,即它们都继承自某一原型。
其中null不是实例,null是空对象,什么都没有。
因为函数Fun1是用户自定义函数,Object,Function是内置函数,都是函数,所以就是通过Function 函数创建的,所以,它们的原型就是Function.prototype.
Function.prototype.上有call和apply方法,所有的函数都继承自它,所以,所有的函数都能够拥有这两个方法。
因为:除了Object.create(),无实参直接创建的对象的原型是null/没有原型,即不继承任何属;其余的对象的原型链上null之前都有一个Object.prototype原型对象。
所以,原型对象和实例的原型都指向了Object.prototype。
3重写原型对象 :
function Foo(){/*...*/} var a1=new Foo(); //用new调用之后就会锁定原型 Foo.prototype={/*...*/}; //创建一个新原型对象,重写Foo的prototype var a2=new Foo();
图3:
注:
新的Foo.prototype 就是Object的实例。
旧的Foo.prototype 不会消失,依然会存在。因为实例a1的原型会指向它,实例a1继承它,在通过new调用生成实例的时候,a1就会锁定它的原型。
Foo.prototype.constructor === Object; //true
a2.constructor === Object; //true
但是,实际上Foo.prototype和a2都没有constructor属性,它们都是继承自Object.prototype。原型才有constructor这个属性,其他对象的constructor都是继承自原型。
4:继承
function SuperType(){ this.property=true; } SuperType.prototype.getSuperValue=function(){ return this.property; }; function SubType(){ this.subproperty=false; } SubType.prototype=new SuperType(); //继承自SuperType /重写了原型 SubType.prototype.getSuperValue=function(){ return this.subproperty; }; var instance=new SubType();
(这张图片源自高程3)
这里也可以比较清楚地看到对象的关系和对象所拥有的属性集合。
这是一个简单的原型继承,通过图解关系就可以看到上面代码,方便理解。
旧的SubType.prototype 依然存在,不过这里它没有实例去引用它。新的SubType.prototype 是作为SuperType的实例存在,继承自SuperType.prototype 。
从instance开始,通过__proto__连接,直到null,就形成了一条原型链,上层的属性会被下层继承。
以上就是我的理解,如果有错误,还请各位前边指正,谢谢。