关于原型对象
- 一个新函数被创建以后,就会根据一组特定的规则为该函数创建一个
prototype
属性。 - 新函数创建时还会创建一个包含
constructor
属性的原型对象。 - 新函数的
prototype
属性指向原型对象;原型对象的constructor
属性指向新函数。 - 调用新函数创建的每个实例都包含一个不能直接访问的内部属性
[[Prototype]]
指向原型对象。
从上面的关系可以看出,原型对象是连接实例与构造函数之间的桥梁。
没有标准的方式直接访问实例的内部属性 [[Prototype]]
(FireFox、 Safari 和 Chrome 在每个对象上都支持一个属性 __proto__
),但存在可以确定实例与原型对象之间关系的方法。
-
Object.prototype.isPrototypeOf(obj)
:如果obj
的内部属性[[Prototype]]
指向调用isPrototypeOf()
方法的对象则返回true
。 -
Object.getPrototypeOf(obj)
:返回obj
的[[Prototype]]
的值(即原型对象的引用)。
关于原型链
每当代码读取某个对象的某个属性时,都会对该属性进行搜索。搜索首先从对象本身开始,如果在对象中找到了所搜索的属性,则返回该属性的值;如果没有找到,则继续搜索该对象的 [[Prototype]]
指针指向的原型对象。这可以看做是一个递归的过程。
// 抽象化描述对象属性的搜索过程
function search (obj, prop) {
var proto = Object.getPrototypeOf(obj);
if (obj.hasOwnProperty(prop)) {
return obj.getOwnPropertyDescriptor(prop);
} else if (proto) {
search(proto, prop);
} else {
return undefined;
}
}
上面的函数描述了对象属性的搜索过程。因为一个对象的原型对象也拥有自己的原型对象,这种层层递进的关系就构成了原型链。事实上,所有对象的原型链的末端都是 Object.prototype
。
var o = {};
console.log(Object.getPrototypeOf(o) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype)); // null
函数作为对象也包含内部属性 [[Prototype]]
,但函数的 prototype
属性与内部属性 [[Prototype]]
并不是同一个概念。函数的 prototype
属性指的是通过该函数创建的实例的原型对象;函数的 [[Prototype]]
属性指的是该函数作为一个对象其内部所指向的原型对象。
例如,所有的对象都是 Object
的实例,因此 Object.prototype
是所有对象原型链的末端;而 Object
本身是 Function
的实例,它的原型对象指向 Function.prototype
。
console.log(typeof Object); // function
console.log(Object.getPrototypeOf(Object) === Object.prototype); // false
console.log(Object instanceof Function); // true
console.log(Object.getPrototypeOf(Object) === Function.prototype); // true
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype); // true