白水源的博客

导航

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

今天再读了《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里比较重要的模块儿,本人才学疏浅、难免疏漏,欢迎指正,共同进步^_^)

 

posted on 2015-12-02 17:33  白水源  阅读(1858)  评论(0编辑  收藏  举报