原型链是JavaScript中比较重要的一个概念,也是JavaScript中实现继承的主要手段。
原型链是什么?要明白这个概念,首先要明白,原型是什么。
原型,就我个人而言,就像我们的姓氏一样(这个比喻不太恰当),天地初开,世界大同,我们人(基类)都是同一种姓氏(基类的原型),我们都从人这个基类下继承了姓氏这么一个属性,当然,你也可以特立独行的去改姓,自立门派,行走江湖(你的后代如果不改姓,那么将会全部都跟你姓,这个没得跑),但是并不会影响到其他人。
值得一提的是,遍历原型的属性是从自身的原型开始往祖先遍历的,一直到找到该属性为止,如果找不到,返回undefine,所以可以通过重写父类方法‘覆盖’父类的原型方法,这就是为什么Array继承了Object的toString()方法,但Array.prototype.toString和Object.prototype.toString不一样的原因,Arrary自己重写了toString()方法。
可以通过hasOwnProperty这个方法来判断该属性是否是自身的属性而非继承,如果是自身,返回true。
而原型链又是什么呢?就像族谱中的族谱线一样。表达那种微妙的继承关系的线,通过这种线,你就可以追根溯源,找到你的祖先。(当然,JS理论上是没有多继承的(其实也可以),而族谱大多是多继承,请无视掉这一点。有那种微妙的继承关系的感觉就行了)
道理虽然是这样,感觉也说得过去。但是,毕竟JavaScript对象不是人,(人可以说每一个都是实例,但是JavaScript对象不行吧)。
每当我们声明一个function的时候,JavaScript都会自动给这个function添加一个prototype(原型)这么一个属性,而prototype的value其实就是很多属性的集合,值得一提的是,prototype里面有一个constructor(构造函数)这么一个属性,顾名思义,这个属性是指向function本身的,或者说,是指向这个原型所对应的的function本身,可以通过这个属性来判断其构造函数是什么。
当我们要实现继承的时候,一般是将父类的实例赋值给子类的原型,如 SubType.prototype = new SupType();这样,子类的原型就有了父类的所有属性,值得注意的是,如果我们创建了子类的实例,在调用子类的constructor属性的时候,会发现,这时返回的是父类的构造函数,如var a = new SubType(); console.log(a.constructor);会返回function SupType(){}(所以我们需要手动修正,在继承之后加上如下操作:SubType.prototype.constructor = SubType。)当我们一层一层的继承的时候,这种实例与原型之间的这种关系,就构成了我们所说的原型链。