F.prototype
我们已经知道new F()会创建一个对象。当使用new F()创建一个对象的时候,该对象F.prototype属性会被设置指向对象的原型,看下面例子:
let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal
alert( rabbit.eats ); // true
上述例子中我们设置了Rabbit.prototype = animal,所以当new Rabbit()的时候,Rabbit的prototype就会指向animal,其对象rabbit的原型即为animal
默认的F.prototype,constructor属性
我们已经知道Javascript里的function是特殊的对象,同时function也是一个构造函数,因为我们可以通过new F()操作来创建对象。每一个函数function都有一个默认的原型对象,即prototype。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数,例如:
function Rabbit() {}
/* default prototype
Rabbit.prototype = { constructor: Rabbit };
*/
这里,Rabbit的prototype指向原型对象,而原型对象里的constructor又指回Rabbit函数本身,我们可以检测一下:
function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }
alert( Rabbit.prototype.constructor == Rabbit ); // true
每个对象都有一个constructor属性,constructor属性指向的是创建当前对象的构造函数,例如:
function Rabbit() {}
// by default:
// Rabbit.prototype = { constructor: Rabbit }
let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}
alert(rabbit.constructor == Rabbit); // true (from prototype)
这里的rabbit对象的constructor指向的是Rabbit函数,因此,基于这样的关系我们还可以这样创建对象:
function Rabbit(name) {
this.name = name;
alert(name);
}
let rabbit = new Rabbit("White Rabbit");
let rabbit2 = new rabbit.constructor("Black Rabbit");
当我们不知道构造函数的时候,这种方法就很有用了。
由于Javascript并不知道constructor的正确值,所以当我们重写了prototype的值时丢失了constructor属性,那么就会很容易出现错误,例如:
function Rabbit() {}
Rabbit.prototype = {
jumps: true
};
let rabbit = new Rabbit();
alert(rabbit.constructor === Rabbit); // false
为了避免这种情况,我们一般选择向prototype添加或删除属性,而不是重写,例如:
function Rabbit() {}
// Not overwrite Rabbit.prototype totally
// just add to it
Rabbit.prototype.jumps = true
// the default Rabbit.prototype.constructor is preserved
如果要重写prototype的话,可以添加上constructor属性,例如:
Rabbit.prototype = {
jumps: true,
constructor: Rabbit
};
// now constructor is also correct, because we added it