JavaScript是一门动态语言,可以很容易地添加、删除和修改属性。这种特性同样适用于原型,包括函数原型和原型对象。但是他是有副作用,这个我们需要了解一下,看清单-1。
/*
清单-1
通过原型,一切都可以在运行时修改
*/
function Apple(){
//定义了一个构造函数,该构造函数中创建了一个swung属性,初始化为布尔值
this.red = true;
}
//通过new操作符调用构造函数,创建实例Ninja
const apple01 = new Apple();
//在实例对象创建完成之后,在原型上添加一个方法
Apple.prototype.isRed = function(){
return this.red;
};
//验证该方法存在于对象中
if(apple01.isRed())
console.log("apple is red");
//使用字面量对象完全重写Apple的原型对象,仅有一个isGreen方法
Apple.prototype = {
isGreen: function() {
return true;
}
}
//尽管我们已经完全替换了Apple的构造器原型,但是实例化后的Apple01对象仍然具有isRed方法,因为对象apple01仍然保持着对旧的Apple原型对象的引用
if(apple01.isRed())
console.log("apple is red!");
const apple02 = new Apple();
if(apple02.isGreen())
console.log("apple is green");
//新创建的apple02实例没有isRed
if(apple02.isRed === undefined)
console.log("apple is not red!");
我们定义了Apple构造器,使用它来创建一个对象实例apple01。构造完成之后,apple01具有red属性,它的原型是Apple原型,仅有一个构造属性red;实例对象创建完成之后,我们在原型对象上添加isRed方法。通过验证可以看到在对象创建完成之后,修改Apple的原型对象。此时apple01也修改了。
如果我们完全重写Apple的原型对象,使其仅含有isGreen方法。通过验证可以看到isRed应可以执行。这说明对象apple01仍然保持着对旧的Apple原型对象的引用。即使Apple原型对象不再指向旧的Apple原型对象,但是旧的原型仍然存在于apple01实例中,通过原型链仍然能够访问isRed方法。但是,如果我们在Apple发生变化之后再创建新的实例对象,此时新对象apple02中的isRed方法就不存在了,对象与函数原型之间的引用关系是在对象创建时建立的。新创建的对象将引用新的原型,原来旧的对象保持着原有的原型。
我们通过断点调试看一下,如【图-1】
【图-1】