论坛首页 Web前端技术论坛

深入剖析Javascript之继承

浏览 10485 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-04-11  
今天要讨论的主题是下面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的继承有了更深一步的了解!
   发表时间:2007-04-12  
分析得挺不错的,最好能结合流行的js library进行分析 如 prototype  ext moonkit module等
0 请登录后投票
   发表时间: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;
  }
0 请登录后投票
   发表时间:2007-05-16  
Object.extend = function(destination, source) {}
0 请登录后投票
   发表时间:2007-05-16  
其实,实用Prototype框架的话,用Class.create()来创建类使用他的风格,我觉得对继承的支持就足够了,而且可以通过mixin实现多继承。比如,我有一个基类A:
js 代码
 
  1. var A = Class.create();  
  2. A.prototype = {  
  3.     initialize: function(){  
  4.         this._init.apply(this,arguments);  
  5.     },
  6.     _init: function(name) {  
  7.         this.name = name;  
  8.     },  
  9.   
  10.     test: function(){  
  11.         alert(this.name);  
  12.     }  
  13. }  

然后,我有一个继承自A的子类B,
js 代码
 
  1. var B = Class.create();    
  2. B.prototype = Object.extend(new A(),    
  3.     {    
  4.         initialize: function(name,type){    
  5.             this._init(name);    
  6.             this.type= type;   
  7.         },    
  8.         test2: function(){    
  9.             alert(this.type);    
  10.         }    
  11.     }    
  12. )           

这样就实现了类继承。注意一个技巧,我们将基类的构造方法抽取出来用_init实现,就是为了在子类中覆盖initialize而又可以初始化父类的成员。接下来,我们可以这么调用:
js 代码
 
  1. var b = new B("B","Class B");  
  2. b.test();  
  3. b.test2()  

至于mixin,其实很简单,等我把我的另一篇文章写完,会详细介绍其中的一些技巧和方法的:

www.iteye.com/topic/79869

0 请登录后投票
   发表时间: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 );  
}
0 请登录后投票
   发表时间:2007-08-02  
哦,对了,m2指向的地址已经改了,所以再增加成员也没用,
那减少成员怎么写?
0 请登录后投票
   发表时间: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的实例变量?
0 请登录后投票
   发表时间:2007-08-02  
哪位高手能研究一下MapEasy API。
0 请登录后投票
   发表时间:2007-08-03  
你说的前两种根本构不成继承。都只是复制或者共享了原型。这样的m1和m2的实例只能说是兄弟,不能说有继承。所以方法一和方法二只能说是一种代码复用的手段,而谈不上继承。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics