在javascript中原型和原型链是一个很神奇的东西,对于大多数人也是最难理解的一部分,掌握原型和原型链的本质是javascript进阶的重要一环。今天我分享一下我对javascript原型和原型链的理解。
一、对象等级划分
我们认为在javascript任何值或变量都是对象,但是我还需要将javascript中的对象分为一下几个等级。
首先Object是顶级公民,这个应该毋庸置疑,因为所有的对象都是间接或直接的通过它衍生的。Function是一等公民,下面会做解释。几个像String,Array,Date,Number,Boolean,Math等内建对象是二等公民。剩下的则都是低级公民。
二、原型prototype
在JavaScript中,原型(prototype)也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个prototype内部属性,这个属性所对应的就是该对象的原型。
prototype作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了 __ proto__ 这个非标准(不是所有浏览器都支持)的访问器(ECMA引入了标准对象原型访问器 Object.getPrototype(object))。在JavaScript的原型对象中,还包含了一个constructior属性,这个属性对应创建所有指向改原型的实例的构造函数。
三、proto和原型链
proto是一个指针,它指的是构造它的对象的对象的prototype,听起来有的拗口。举个例子吧!
如上面代码,o是Object的一个实例,所以o的proto指针指向构造o的Object的prototype。这样的意义在于o可以使用Object.prototype里面的方法,例如toString(),o在访问toString方法时,首先会在自身寻找,如果没有找到则会在proto也就是Object.prototype上面查找。
可以说几乎所有的javascript对象都有proto这样一个指针包括Object,我们来看一看
其实a = 1就相当于a = new Number(1)。可以看到所有的内建对象以及Object的proto指向的都是一个匿名函数,也就可以认为它们其实也是function的一个实例,所以之前会说function是一等公民。
那么原型链到底是什么呢?我们展开a.proto也就是Number.prototype对象,它是没有toString()的方法的,但是对于a来说它其实是可以调用toString的方法的,这就是原型链的作用。看下面代码
看上面代码和结果,我们沿着a的proto一直访问会到达Object的prototype,也就是说a调用toString方法最终其实是访问Object.prototype的toString方法。那么a的原型链就是由Number.prototype和Object.prototype组成,当a访问一个方法或属性时,它会先在自身查找,然后再沿原型链找,找到则调用,没找到报错。为了印证这一点,我们在Number.prototype上面加一个toString的方法。
可以看到a调用的是Number.prototype的toString方法,在找到之后就停止。在javascript中,几乎所有的对象的原型链的终点都是Object.prototype
总结
proto是实现原型链的关键,而prototype则是原型链的组成。
proto与prototype的区别。
var 对象 = new 函数()
对象.proto === 函数.prototype