原型、原型链
理解JavaScript原型
彻底理解JavaScript原型
原型
原型是一个对象,所有对象都可以成为原型,其它对象可以通过它实现属性继承。原型真正魅力体现在多个实例共用一个通用原型的时候。如果试图获取一个主数据类型的原型时,它会被强制转化成了一个对象。
构造函数提供了一种方便的跨浏览器机制,这种机制允许在创建实例时为实例提供一个通用的原型。函数A的原型属性(prototype property )是一个对象,当这个函数被用作构造函数来创建实例时,该函数的原型属性将被作为原型赋值给所有对象实例,即所有实例的原型引用的是函数的原型属性。即所有实例的原型引用的是函数的原型属性。
如果修改了构造函数的原型属性,那么已经存在的该构造函数的实例将获得构造函数的最新版本。
如果修改了构造函数的原型属性所指向的对象,那么新创建实例时实例原型所指向的是新对象,但是这并不会影响已经创建的实例的原型。
要注意区分原型属性和原型对象:
object.prototype
-- 原型属性
Object.getPrototypeOf(object) 、object.__proto__ 、object.constructor.prototype
-- 原型对象,真正的原型
constructor -- 是原型对象的属性,对应创建所有指向该原型的实例的构造函数
对于所有对象,都有__proto__
属性,这个属性对应该对象的原型
对于所有函数对象,除了__proto__
属性之外,还有prototype
属性,当一个函数被用作构造函数来创建实例时,该函数的prototype
属性值将被作为原型赋值给所有对象实例(也就是设置实例的__proto__
属性)
通过修改原型可以达到继承的效果,如:
var a = {};
a.__proto__ = Array.prototype;
a.length; // 0
{% img /2016/10/20/javascript-base/prototype.png 原型示意图 %}
原型链
所有的对象在默认的情况下都有一个原型,因为原型本身也是对象,所以每个原型自身又有一个原型,对象的原型指向对象的父,而父的原型又指向父的父,我们把这种通过原型层层连接起来的关系撑为原型链。这条链的末端一般总是默认的对象原型。
所有对象的原型都将追溯到"Object{}"对象,Object对象本身是一个函数对象。如果a的原型属于A的原型链,表达式 a instance of A 值为true。
原型的继承机制是发生在内部且是隐式的。当想要获得一个对象a的属性foo的值,javascript会在原型链中查找foo的存在,如果找到则返回foo的值,否则undefined被返回。如果想要覆盖原型链上的一些属性,就可以直接在对象中定义这些属性。
hasOwnProperty
是Object.prototype
的一个方法,该方法能判断一个对象是否包含自定义属性而不是原型链上的属性,hasOwnProperty
是JavaScript中唯一一个处理属性但是不查找原型链的函数。
二维作用域链查找:当代码需要查找一个属性或者描述符的时候,首先会通过作用域链来查找相关的对象;一旦对象被找到,就会根据该对象的原型链来查找属性。