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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值