在本文中主要探讨JavaScript中原型的相关知识。
JavaScript中所有的函数默认都有一个名为prototype(原型)的公有并且不可枚举的属性,这个属性是一个指针,它会指向一个对象。
function Foo(){
}
Foo.prototype; //{ }
而这个对象通常被称为Foo的原型对象,用FooPrototype(自己假想的)表示。Foo.prototype = FooPrototype;在默认情况下,所有原型对象都会获得一个constructor属性,这个属性包含一个指向prototype属性所在函数的指针。当我们使用new来调用这个函数Foo创建一个实例时,该实例的内部会包含一个指针(内部属性),指向这个构造函数的原型对象,这个指针叫[[prototype]],可以使用__proto__来访问这个原型对象。
function Foo(){
}
Foo.__proto__ === Function.prototype // true
var a = new Foo();
a.__proto__ === Foo.prototype; // true
Object.getPrototypeOf(a) === Foo.prototype; // true
Foo.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null;// true
Foo.prototype.constructor === Foo; // true
a.constructor === Foo; // true
a.constructor === Foo.prototype.constructor; // true
这里有个比较疑惑的点在于a.constructor,难道a也有.constructor属性?实际上a本身并没有.constructor属性,而且,虽然a.constructor确实指向Foo函数,但是这个属性并不是表示a有Foo“构造”的。
实际上,.constructor引用同样被委托给了Foo.prototype,而Foo.prototype.constructor默认指向Foo。
举个例子:
function Foo(){
}
Foo.prototype = { /**/ };//创建一个新原型对象,相当于new Object()。
var a1 = new Foo();
a1.constructor === Foo;//false
a1.constructor === Object.prototype.constructor;//true
a1.constructor === Object;//true
a1并没有.constructor属性,所以它会委托[[prototype]]链上的Foo.prototype。但是这个对象也没有.constructor属性(不过默认的Foo.prototype对象有这个属性!),所以它会继续委托,这次它会委托给委托链顶端的Object.prototype。这个对象有.constructor属性,指向内置的Object(...)函数。
当然,我们可以给Foo.prototype添加一个.constructor属性,这需要手动添加一个符合正常行为的不可枚举属性。
function Foo(){
}
Foo.prototype = { /**/ };
Object.defineProperty({
enumerable:false,
writable:true,
configurable:true,
value:Foo//让.constructor指向Foo
})
JavaScript里其他的引用类型,如Array,Date,RegExp,Function,String,Number,Boolean等。举例如下:
var a = new Array();
a.__proto__ === Array.prototype; // true
a.__proto__.__proto__ === Object.prototype; // true
a.__proto__.__proto__.__proto__ === null; // true
Array.prototype.constructor === Array;//true
a.constructor === Array;//true
a.constructor === Array.prototype.constructor;//true
Array.constructor === Function;// true
网友评论