`
j2eeqk
  • 浏览: 10991 次
  • 性别: Icon_minigender_2
  • 来自: 湖北武汉
文章分类
社区版块
存档分类
最新评论

深入剖析Javascript之继承

阅读更多
今天要讨论的主题是下面3种方案的对比:
前提:
var m1 = function(){};
var m2 = function(){};

要对比的3种方案是:
1>Object.extend( m1.prototype, m2.prototype );
2>m1.prototype = m2.prototype;
3>m1.prototype = new m2();

下面对各种方案先预先给予说明:
1>第一种方案是将m2.prototype该对象中所有成员拷贝(覆盖)到m1.prototype对象中。
看代码:
var m1 = function(){};
var m2 = function(){};
var o2 = new m2();
o2.name = 'qk';
m2.prototype.print = function()
{
    alert( this.name );
}
Object.extend( m1.prototype, m2.prototype );

到此,我们可以想象,m2.prototype中的成员变量print已经拷贝到m1.prototype中,即,凡m1对象便拥有print成员。假如我们试图创建m1的对象,
var o1 = new m1();

则我们可以调用o1.print();但由于m1对象中不存在name属性,故会是undefined。问题在哪?是因为m2.prototype对象的成员中包含了m2的实例变量name,这种设计方案是不合理的(这里只是为了演示所用,现实中是不会出现类似的代码的,下同)。
2>第二种方案是将m1.prototype对象的指针指向m2.prototype的内存地址。或m1.prototype对象只是m2.prototype对象的一个引用。试图改变m2.prototype内存地址后不会影响m1.prototype对象成员的变化。看代码:
var m1 = function(){};
var m2 = function(){};
var o2 = new m2();
o2.name = 'qk';
m2.prototype.print = function()
{
    alert( this.name );
}
m1.prototype = m2.prototype;
// 改变m2.prototype
m2.prototype = {0:0};
// 打印
var o1 = new m1();
for( var key in o1 )
{
	alert( key + '=>' + o1[ key ] );
}

不过,如果对m2.prototype对象的成员进行增加或删除,m1.prototype就会改变。看代码:
var m1 = function(){};
var m2 = function(){};
var o2 = new m2();
o2.name = 'qk';
m2.prototype.print = function()
{
    alert( this.name );
}
m1.prototype = m2.prototype;
// 增加m2.prototype对象的成员。
m2.prototype[0] = 0;
// 打印
var o1 = new m1();
for( var key in o1 )
{
	alert( key + '=>' + o1[ key ] );
}

3>第二种方案是让m1.prototype链式继承m2.prototype的所有成员。即m1.prototype继承m2.prototype,m2.prototype继承Object.prototype.它于第二种方案的不同是,第二种方案中,m1.prototype只是m2.prototype对象的一个引用。只有增加或删除m2.prototype成员才会引起m1.prototype成员的变化。它于第一种方案的不同是,第一种方案中,m1.prototype成员只会增加,不会减少。而这里是链式继承。看代码:
var m1 = function(){};
var m2 = function(){};
var o2 = new m2();
o2.name = 'qk';
m2.prototype.print = function()
{
    alert( this.name );
}
m1.prototype = new m2();
// 打印
var o1 = new m1();
for( var key in o1 )
{
	alert( key + '=>' + o1[ key ] );
}

此时,o1对象访问属性的顺序是:
m1.prototype对象成员 > m2的实例变量 > m2.prototype对象成员 > m1的的实例变量

好了,介绍完这3种“继承”后,希望大家对javascript的prototype的继承有了更深一步的了解!
分享到:
评论
13 楼 hax 2007-08-04  
js本质上只有属性。如果属性是一个函数,则像x.f()这样的调用,在f内的this会指向x,从而变成所谓方法。

因此本质上不存在继承方法,只有继承属性。这个有什么不能接受呢?所谓继承,就是获得其被继承者的所有特性,不是吗。就算是java,子类一样继承了父类的所有特性,不仅包括方法,也包括成员变量,不仅包括public,也包括protectd, private的(不过就是不再能直接访问private而已)。

12 楼 weiqingfei 2007-08-03  
hax 写道
第三种可以算继承,因为虽然不是类的继承,但是可以算是原型继承,也就是继承了作为原型的对象实例上的所有属性。而前两种只是复制或共享原型实例,最多只能说m1继承了m2的原型(或其副本),但是没有继承m2。


前两种不算继承倒是比较明显。

第三种,“继承了作为原型的对象实例上的所有属性”,在继承《方法》属性上还算可以理解,继承《Property》属性上实在不能让人接受。
11 楼 hax 2007-08-03  
第三种可以算继承,因为虽然不是类的继承,但是可以算是原型继承,也就是继承了作为原型的对象实例上的所有属性。而前两种只是复制或共享原型实例,最多只能说m1继承了m2的原型(或其副本),但是没有继承m2。
10 楼 weiqingfei 2007-08-03  
第三种能算是继承么?
方法的prototype指向的是另一个方法的实例,这可是实例呀,就算子方法new再多,父方法也只有一个实例。
9 楼 hax 2007-08-03  
你说的前两种根本构不成继承。都只是复制或者共享了原型。这样的m1和m2的实例只能说是兄弟,不能说有继承。所以方法一和方法二只能说是一种代码复用的手段,而谈不上继承。
8 楼 marshal2004 2007-08-02  
哪位高手能研究一下MapEasy API。
7 楼 ntucz 2007-08-02  
var m1 = function(){};  
var m2 = function(){};  
var o2 = new m2();  
o2.name = 'qk';  
m2.prototype.print = function()  
{  
alert( this.name );  
}
m1.prototype = new m2();
m1.prototype.i = 'i';
// 打印  
var o1 = new m1();  
o1.love='love';
for( var key in o1 )
{  
alert( key + '=>' + o1[ key ] );  
}
怎么看不到m2的实例变量?
6 楼 ntucz 2007-08-02  
哦,对了,m2指向的地址已经改了,所以再增加成员也没用,
那减少成员怎么写?
5 楼 ntucz 2007-08-02  
var m1 = function(){};  
var m2 = function(){};  
var o2 = new m2();  
o2.name = 'qk';  
m2.prototype.print = function()  
{  
alert( this.name );  
}
m1.prototype = m2.prototype;  
// 改变m2.prototype,内存地址改变,但m1指向原来的地址 
m2.prototype = {0:0}; 
// 增加m2.prototype对象的成员。  
m2.prototype[1] = 1;
// 打印  
var o1 = new m1();  
for( var key in o1 )
{  
alert( key + '=>' + o1[ key ] );  
}

为什么只打印print=>function()  
{  
alert( this.name );  
}
4 楼 笨笨狗 2007-05-16  
其实,实用Prototype框架的话,用Class.create()来创建类使用他的风格,我觉得对继承的支持就足够了,而且可以通过mixin实现多继承。比如,我有一个基类A:<br/>
<div class='code_title'>js 代码</div>
<div class='dp-highlighter'>
<div class='bar'> </div>
<ol class='dp-c'>
    <li class='alt'><span><span class='keyword'>var</span><span> A = Class.create();  </span></span> </li>
    <li class=''><span>A.prototype = {  </span> </li>
    <li class='alt'><span>    initialize: <span class='keyword'>function</span><span>(){  </span></span> </li>
    <li class=''><span>        <span class='keyword'>this</span><span>._init.apply(</span><span class='keyword'>this</span><span>,arguments);  </span></span> </li>
    <li class='alt'><span>    },<br/>
    </span></li>
    <li class='alt'><span>    _init: <span class='keyword'>function</span><span>(name) {  </span></span> </li>
    <li class=''><span>        <span class='keyword'>this</span><span>.name = name;  </span></span> </li>
    <li class='alt'><span>    },  </span> </li>
    <li class=''><span>  </span> </li>
    <li class='alt'><span>    test: <span class='keyword'>function</span><span>(){  </span></span> </li>
    <li class=''><span>        alert(<span class='keyword'>this</span><span>.name);  </span></span> </li>
    <li class='alt'><span>    }  </span> </li>
    <li class=''><span>}  </span> </li>
</ol>
</div>
<br/>
然后,我有一个继承自A的子类B,
<div class='code_title'>js 代码</div>
<div class='dp-highlighter'>
<div class='bar'> </div>
<ol class='dp-c'>
    <li class='alt'><span><span class='keyword'>var</span><span> B = Class.create();    </span></span> </li>
    <li class=''><span>B.prototype = Object.extend(<span class='keyword'>new</span><span> A(),    </span></span> </li>
    <li class='alt'><span>    {    </span> </li>
    <li class=''><span>        initialize: <span class='keyword'>function</span><span>(name,type){    </span></span> </li>
    <li class='alt'><span>            <span class='keyword'>this</span><span>._init(name);    </span></span> </li>
    <li class=''><span>            <span class='keyword'>this</span><span>.type= </span></span><span><span>type</span></span><span><span/><span class='string'/><span>;   </span></span> </li>
    <li class='alt'><span>        },    </span> </li>
    <li class=''><span>        test2: <span class='keyword'>function</span><span>(){    </span></span> </li>
    <li class='alt'><span>            alert(<span class='keyword'>this</span><span>.type);    </span></span> </li>
    <li class=''><span>        }    </span> </li>
    <li class='alt'><span>    }    </span> </li>
    <li class=''><span>)           </span> </li>
</ol>
</div>
<br/>
这样就实现了类继承。注意一个技巧,我们将基类的构造方法抽取出来用_init实现,就是为了在子类中覆盖<span>initialize</span>而又可以初始化父类的成员。接下来,我们可以这么调用:<br/>
<div class='code_title'>js 代码</div>
<div class='dp-highlighter'>
<div class='bar'> </div>
<ol class='dp-c'>
    <li class='alt'><span><span class='keyword'>var</span><span> b = </span><span class='keyword'>new</span><span> B(</span><span class='string'>"B"</span><span>,</span><span class='string'>"Class B"</span><span>);  </span></span> </li>
    <li class=''><span>b.test();  </span> </li>
    <li class='alt'><span>b.test2()  </span> </li>
</ol>
</div>
<br/>
至于mixin,其实很简单,等我把我的另一篇文章写完,会详细介绍其中的一些技巧和方法的:<br/>
<br/>
<a href='http://www.iteye.com/topic/79869'>www.iteye.com/topic/79869</a><br/>
<br/>
3 楼 kebin8 2007-05-16  
Object.extend = function(destination, source) {}
2 楼 qianjinfu 2007-04-12  
 m2.prototype = Object.extend(new m1, m2.prototype ); 


m1是父类,m2是子类
prototype中继承的代码:
  Object.extend = function(destination, source) {
  for (property in source) {
    destination[property] = source[property];
  }
  return destination;
  }
1 楼 jianfeng008cn 2007-04-12  
分析得挺不错的,最好能结合流行的js library进行分析 如 prototype  ext moonkit module等

相关推荐

    深入剖析JavaScript面向对象编程

    本文将深入探讨JavaScript中的面向对象编程,特别是关于构造函数的继承。 首先,我们来理解构造函数在JavaScript面向对象编程中的作用。构造函数是一种特殊类型的函数,用于初始化新创建的对象。例如,我们可以定义...

    深入剖析JavaScript instanceof 运算符

    理解`instanceof`的工作原理,我们需要深入到JavaScript的原型链(prototype chain)和`GetValue`方法。根据ECMAScript-262 Edition 3标准,`instanceof`运算符的工作原理如下: 1. 评估`RelationalExpression`(即...

    深化剖析JavaScript面对对象编程_.docx

    本文将深入探讨JavaScript中的面向对象编程,特别是构造函数的继承机制。 首先,我们来看构造函数的继承。构造函数在JavaScript中用于创建特定类型的对象。例如,`Animal`和`Cat`是两个构造函数,分别代表“动物”...

    JavaScript深度剖析课件下载

    这门“JavaScript深度剖析”课程显然旨在帮助开发者深入理解其内部机制,提升技能水平。通过下载的课件,学习者可以系统地掌握JavaScript的各种关键概念和高级特性。 首先,JavaScript是一种解释型的、基于原型的...

    深入浅出javascript源代码.

    在这个压缩包中,可能包含了一系列章节或教程,逐一剖析JavaScript的关键概念和技术。 首先,我们要了解JavaScript的基础。JavaScript是一种解释型的、基于原型的、动态类型的编程语言。它的主要特点是弱类型和事件...

    JavaScript深度剖析.zip

    这个名为"JavaScript深度剖析.zip"的压缩包文件显然包含了关于JavaScript深入学习的教学资源,可能包括讲义、代码示例、练习题和解剖案例等,旨在帮助用户提升JavaScript编程技能。 JavaScript的核心知识点涵盖了...

    深入理解JavaScript作用域共12页.pdf.zip

    JavaScript作用域是编程中至关重要的概念,尤其是在JavaScript这种动态类型的脚本语言中。它规定了变量、函数以及其它标识符的可见...这份12页的PDF文档将详细剖析这些关键点,是JavaScript学习者不可多得的参考资料。

    JavaScript_深度剖析(从入门到精通).doc

    JavaScript 深度剖析 JavaScript 是一种广泛应用于Web开发的轻量级编程语言,由Netscape公司的Brendan Eich在1995年设计,最初被命名为LiveScript。JavaScript 不是Java的子集,尽管名字相似,两者在设计哲学和语法...

    悟透JavaScript-pdf版

    在对象和原型链方面,《悟透JavaScript》深入剖析了JavaScript的面向对象特性,包括构造函数、原型、原型链、继承机制。这部分内容对于理解和编写可维护的代码至关重要,因为JavaScript的面向对象模型与传统的类继承...

    Javascript 设计模式 很经典 第一本

    《Pro JavaScript Design Patterns》是一本不可多得的好书,它不仅全面介绍了JavaScript设计模式的相关知识,还深入剖析了面向对象编程的核心原理和技术细节。对于想要提升自己JavaScript编程水平的开发者来说,这...

    JavaScript核心技术开发解密 随书源代码

    本书“JavaScript核心技术开发解密”由阳波撰写,旨在深入剖析JavaScript的核心技术,帮助读者掌握这门语言的精髓。书中包含232页的内容,覆盖了JavaScript的各个方面,为开发者提供了宝贵的资源和实践指导。 ...

    JavaScript学前书籍.doc

    这本书深入剖析了JavaScript的本质,包括对象、函数、继承和数组等多个关键概念,对于深化对JavaScript语言的理解非常有帮助。反复阅读可以不断巩固知识,提高编程水平。 在学习过程中,不断实践和反思是提升的关键...

    JavaScript语言精粹 pdf

    - **原型链**:深入理解JavaScript中的原型链机制,明白对象继承的原理。 - **this关键字**:掌握this在不同上下文中指向的对象,理解其作用于函数调用模式的变化。 #### 3. 高级特性 - **异步编程**:学习事件循环...

Global site tag (gtag.js) - Google Analytics