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

来源:互联网 发布:java 实体类转json 编辑:程序博客网 时间:2024/06/05 17:02


今天再读了《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();     //Helloalert(Person.prototype.isPrototypeOf(proto));    //falsealert(Person.prototype.isPrototypeOf(p));    //truealert(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();     //erroralert(Person.prototype.isPrototypeOf(proto));    //falsealert(Person.prototype.isPrototypeOf(p));    //falsealert(proto.isPrototypeOf(p));    //true
复制代码

上述代码非常清晰的告诉我们:proto里保存的依然是原来的原型对象,p此时访问的还是原来的原型对象。

 

综上,个人感觉这两部分的内容不应该放在一块儿说,很容易让人迷糊,其次,看问题,一定能进得去、跳的出,遇到死角,站在更高的角度看一下,就会有新的发现,自己在看这块儿时一直拐不过来弯儿,分明前边说了有动态性,后边确没有体现,并且还相违背,这分明不合理,后来才发现,这其实是两码事儿,应该分开来理解。

(另:这是JS里比较重要的模块儿,本人才学疏浅、难免疏漏,欢迎指正,共同进步^_^)

0 0
原创粉丝点击