您的位置:首页 > Web前端 > JavaScript

JS原型的动态性及实例与原型的关系

2017-04-10 18:10 162 查看



今天再读了《JS高程》的第六章,有了些深入的感悟和理解,总结分享一下。
创建对象的方式有很多,有一种是动态原型模式,最实用的是构造函数与原型组合的模式,原型的动态性在这两个模式里都有所体现,我本人的理解是:前者的“动态”是通过一些判断,看方法是否存在来决定是否对原型进行初始化,同时,在构造函数内部对原型的修改会立即体现在所有的实例中,后者的“动态”是主要是说无论是先创建实例还是先修改原型,对原型对象所做的修改都会立即反应在实例中,针对后者来个栗子(栗子1):

function Person(){}
var p = new Person();
Person.prototype.sayHello = function(){
alert("Hello!");
}
p.sayHello();    //弹出:Hello


其实,实例与原型之间的关联纽带就是一个定向指针,因此,我感觉构造函数与实例某种程度上是平等关系,只不过构造函数拥有原型指过来的一个指针(constructor)。
 
到这里,一切都很好理解,偏偏文章接下来有扩展了一点儿内容把我搞迷糊了,直接上码(栗子2):

function Person(){}
Person.prototype = {
constructor : Person,
name : "Tom",
age : 29,
sayName : function(){
alert(this.name);
}
}
var p = new Person();
p.sayName();    //弹出:"Tom"


那好,既然上边说了,原型有动态性,那我这样写(栗子3):

function Person(){}
var p = new Person();
Person.prototype = {
constructor : Person,
name : "Tom",
age : 29,
sayName : function(){
alert(this.name);
}
}
p.sayName();    //error


按理说,我实例调用了原型上的方法,应该弹出“Tom”啊,事实上却报错:“undefined is not a function”。
其实,这已经不再是原型动态不动态的问题了,而是实例与新、旧原型对象之间的问题。另外原型与实例间关系,我们可以用isPrototypeOf或者instanceof等来判断。
我们都看到了,栗子1与栗子2、3对原型的修改方式是不一样的,栗子1相当于纯粹的给原型这个对象添加了一个方法,而栗子2、3用的是字面量法创建了一个新的原型(相当于新建一个对象),完完全全,彻彻底底地覆盖了原来的原型对象,只不过用一句“constructor:Person;”伪装了一下,仔细的读者或许会发现我在第二段的说明是给"修改"这个词加粗了,栗子1只是“修改”,栗子2、3是“新建覆盖”。
栗子2中创建实例对象时,原来的原型已经被新建的原型覆盖了,因此能够访问到这个方法。而栗子3中,当创建实例时,它的指针指向的还是之前的原型,即便后来又新建了一个原型对象,这个指针依然没变,一次在原来原型上是访问不到这个方法的,故报错。语言的描述显得很干巴巴,我们再来个栗子(栗子4):

function Person(){}
Person.prototype = {
name : "Tom",
age : 29,
sayHello : function(){
alert("Hello");
}
}
var proto = Person.prototype;
var p = new Person();
p.syaHello();     //Hello
alert(Person.prototype.isPrototypeOf(proto));    //false
alert(Person.prototype.isPrototypeOf(p));    //true
alert(proto.isPrototypeOf(p));    //true


上述代码非常清晰的告诉我们:proto里保存的始终是原来的原型对象,而alert里的Person.prototype是已经被覆盖了的新的原型对象,p此时访问的也是新的原型对象。
最后来个栗子(栗子5):

function Person(){}
Person.prototype = {
var proto = Person.prototype;
var p = new Person();
name : "Tom",
age : 29,
sayHello : function(){
alert("Hello");
}
}
p.syaHello();     //error
alert(Person.prototype.isPrototypeOf(proto));    //false
alert(Person.prototype.isPrototypeOf(p));    //false
alert(proto.isPrototypeOf(p));    //true


上述代码非常清晰的告诉我们:proto里保存的依然是原来的原型对象,p此时访问的还是原来的原型对象。
 
综上,个人感觉这两部分的内容不应该放在一块儿说,很容易让人迷糊,其次,看问题,一定能进得去、跳的出,遇到死角,站在更高的角度看一下,就会有新的发现,自己在看这块儿时一直拐不过来弯儿,分明前边说了有动态性,后边确没有体现,并且还相违背,这分明不合理,后来才发现,这其实是两码事儿,应该分开来理解。
(另:这是JS里比较重要的模块儿,本人才学疏浅、难免疏漏,欢迎指正,共同进步^_^)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: