原型与原型链
原型及原型链是什么
JS中的对象,在创建时都会有一个内置属性,即__proto__
属性,该属性指向一个对象,事实上可以理解为对另一个对象的引用。而被引用的对象就是原型对象。与之相对的,所有函数也可通过一个内置属性prototype
指向原型对象。
var a = new Object()
a.__proto__ === Object.prototype // true
var b = {}
b.__proto__ === Object.prototype // true
当对象是由构造器函数生成的时候,结果也是一样。
function F() {}
var c = new F()
c.__proto__ === F.prototype // true
c.__proto__.__proto__ === Object.prototype // true
在上面的例子中,c.__proto__.__proto__
即构成了一个连接到顶层Object.prototype
原型对象的链接,这就是原型链。通过以上例子,可以简单的得到
对象.__proto__ === 对象的构造函数.prototype
Function.__proto__ === Function.prototype // true 函数也是一种对象
Function.__proto__.__proto__ === Object.prototype // true
事实上,__proto__
和prototype
只是对象和函数中的两个属性名罢了,它们分别指向一个原型对象,顶层的原型对象就是Object.prototype
所指向的对象。因为Object.prototype
指向的是一个对象,那么该对象也有一个__proto__
属性,又因为Object.prototype
是指向顶层原型对象,那么
Object.prototype.__proto__ === null // true
原型的作用
说了这么多,接着说原型的作用。原型存储着一些共有的属性及方法。所有对象(函数也是种对象)都可通过原型链来访问其中的属性。另外,既然__proto__
和prototype
只是代表引用,那么就可以改变它们引用的原型对象。
如果改变原型对象属性,会影响到与之关联的其他对象对其属性的调用,毕竟对于对象都是引用而非拷贝,这需要特别注意。
var x1 = {a:2};
var x2 = Object.create(x1);
x2.a; // 2
在上面的代码中,将x1
设置为x2
的原型,x2
此时就能访问x1
对象的属性。
所以只要理解了在对象及函数背后含有指向另一个对象的属性就好理解原型及原型链了。原型是为了方便存放一些公用属性及方法,原型链就是用来指向原型的就好了。
另外,如果原型链中存在相同的属性名时,先链接到的属性会屏蔽后面的相同属性。
var x1 = {a:1};
x1.__proto__.a = 2;
x1.a // 1
delete x1.a // true
x1.a // 2
从上面的例子中可以看到,在对象内部及对象原型设置拥有相同属性名的a
,此时调用x1.a
得到的是1
,当删除自身属性a
后,原型中的a
就会浮现出来。
可以通过Object.getPrototypeOf(obj)
来获取对象的原型。