日期:2014-05-16  浏览次数:20369 次

JavaScript中的继承
最近看Sencha的源码被那4万多行代码震慑了。
里面使用了不少继承,我也忘的差不多了,这里权当复习一下。

1.对象冒充
function magician(name,skill){
  this.name = name;
  this.skill = skill;
  this.perform = function(){
  alert(this.name+":"+this.skill+"!!!");
  }
}

function magicgirl(name,skill,age){
  this.newMethod = magician;
  this.newMethod(name,skill);
  delete this.newMethod;	//删除该指针			
  this.age = age;
  this.performMore = function(){
  alert("A maigc girl only "+this.age+" years old!");
  }
}


var me = new magician("Young","fireball");
var sister = new magicgirl("Nina","lightning",16);
me.perform();
sister.perform();
sister.performMore();

输出
Young:fireball!!!
Nina:lightning!!!
A maigc girl only 16 years old!
类貌似不是很典型..至少继承的结果是好的..
对象冒充的优点是支持多继承,例如magicgirl继可继承girl又可继承magician,例如
function magicgirl(name,skill,age){
  this.newMethod = girl;  //假设有一girl类
  this.newMethod(name);
  delete this.newMethod;

  this.newMethod = magician;
  this.newMethod(name,skill);
  delete this.newMethod;	
		
  this.age = age;
  this.performMore = function(){
  alert("A maigc girl only "+this.age+" years old!");
  }
}

当然如果被继承的两个父类如果有同名的属性或方法,后执行而继承的属性/方法会覆盖之前所继承的。
还有就是不要忘了先将自定义的方法(本例中newMethod)的引用删除(防止以后被误调用),再添加新的属性/方法。

2.call方法(与方法1非常相似,只列出子类)
function magicgirl(name,skill,age){
  //this.newMethod = magician;
  //this.newMethod(name,skill);
  //delete this.newMethod;
  magician.call(this,name,skill);	
		
  this.age = age;
  this.performMore = function(){
  alert("A maigc girl only "+this.age+" years old!");
  }
}

call方法能劫持另外一个对象的方法,继承另外一个对象的属性。
本例中利用传入的this(也就是magicgirl的实例对象)来劫持magician类的对象属性和对象方法

3.apply方法(与call一样,只是从第2个起的参数全放在一个数组中传递)
function magicgirl(name,skill,age){
  //this.newMethod = magician;
  //this.newMethod(name,skill);
  //delete this.newMethod;
  //magician.call(this,name,skill);	
  magician.apply(this,new Array(name,skill));
		
  this.age = age;
  this.performMore = function(){
  alert("A maigc girl only "+this.age+" years old!");
  }
}


4.原型链方法
function magician(){
}
			
magician.prototype.name = "";
magician.prototype.skill = "";
magician.prototype.perform = function(){
  alert(this.name+":"+this.skill+"!!!");
}
			
function magicgirl(){
}
			
magicgirl.prototype = new magician();	
magicgirl.prototype.age = "";
magicgirl.prototype.performMore = function(){
  alert("A maigc girl only "+this.age+" years old!")
}


var me = new magician();
var sister = new magicgirl();
me.name = "Young";
me.skill = "fireball";
sister.name = "Nina";
sister.skill = "lightning";
sister.age = 16;
me.perform();
sister.perform();
sister.performMore();

该方式是将子类的prototype指向父类的实例对象,因而获得父类的prototype属性/方法。
优点是可以使用instanceof来判断类类型(向父类兼容,类似Java)
缺点则是不支持多重继承,并且父类属性都设置为protoype容易引起问题(参见上一篇blog之类的构造方式)

5.混合方法
function magician(name,skill){
  this.name = name;
  this.skill = skill;
}

magician.prototype.perform = function(){
  alert(this.name+":"+this.skill+"!!!");
}
			
function magicgirl(name,skill,age){
  magician.call(this,name,skill);
  this.age = age;
}
			
magicgirl.prototype = new magician();	
magicgirl.prototype.performMore = function(){
  alert("A maigc girl only "+this.age+" years old!")
}

var me = new magician("Young","fireball");
var sister = new magicgirl("Nina","lightning",16);
me.perform();
sister.perform();
sister.performMore();

综合了1-4方法的优点,避免了缺点。好了,"几乎"完美了。
至于多重继承造成的覆盖问题,C++中也是存在的,这里就不把问题搞复杂了。
有什么更好的方法欢迎指教,谢谢!