JavaScript原型模式 中篇

原型的动态性
什么叫原型的动态性?对原型对象的修改会作用于实例,
即便实例是在原型对象修改前创建的。
举一个例子:
function Person() {};
Person.prototype.username = 'luohao';
Person.prototype.password = '123456';
Person.prototype.register = function() {
console.log("hello " + this.username + "!");
}
var person1 = new Person();
Person.prototype.hometown = '武汉';
console.log(person1.hometown);
person1的创建是在Person.prototype.hometown的添加之后,
但是依旧能够在person1中访问到hometown属性。
这就是原型的动态性。无论实例的创建是在原型修改之前,
还是在原型的修改之后,最终都会作用于实例。
原型为什么可以做到动态性?这才是要点。
维系原型和实例的是一个指针。实例中有一个指向原型的指针。
更进一步说,实例中并没有保存原型的副本,而是保存有指向原型的指针。
如果实例中保存的是原型的副本,那么原型的更新是不会作用于原型副本。
但是实例中保存的恰巧是原型的指针。当在实例中调用某个方法或者属性时,
首先会在当前实例中进行搜索。如果找到了,那么停止搜索。如果没有找到,
那么继续上溯,到原型中去搜索。而原型中刚好更新了hometown属性,
所以能够访问到。以上所说皆是真理。下面来一个否定之否定,完成超越。
请看代码:
function Person() {};
Person.prototype.username = 'luohao';
var person1 = new Person();
Person.prototype = {
hometown: '武汉'
}
console.log(person1.hometown);
此时person1无法访问到hometown。为什么?原型对象的动态性失效了吗?
这涉及到原型对象声明形式的问题,其实,不仅仅是形式的问题,这背后
涉及到更深层次的问题。大而化简,一句话就是:
采用Person.prototype.hometown的形式是在原来原型的基础上新添加的属性。
实例中原型指针指向的原型仍然是原来的原型对象。原型对象中的constructor指针
指向的也是person对象。所以,原型的自动更新有效。
但是,采用Person.prototype = {hometown: '武汉'}的形式不是在原来的原型上
进行修改而是重新构造了一个原型,此时实例中的原型指针指向的是原来的原型对象,
但是实例的构造函数的原型指针指向的新创建的原型对象。新创建的原型对象包含
hometown属性,但是原来的原型不包含hometown属性。所以,实例无法访问到hometown属性。
采用重写原型后的构造函数实例化一个对象person2,此时person2实例可以访问到hometown属性。
但是新创建的原型中的constructor指针已经不在指向Person构造函数而是指向Object。
这也是一个坑。当然,你可以进行微调。
function Person() {};
Person.prototype.username = 'luohao';
var person1 = new Person();
Person.prototype = {
constructor: Person,
hometown: '武汉'
}
console.log(person1.hometown);
var person2 = new Person();
console.log(person2.hometown);

猜你喜欢

转载自blog.csdn.net/qq_23143555/article/details/80716846