本文详细解析 JavaScript 中实现继承的五种核心方式:对象冒充、call()、apply()、原型链及混合模式。通过具体代码示例,对比各方法的语法格式、适用场景及局限性,重点说明构造函数与原型链结合的最佳实践,帮助开发者根据实际需求选择最优继承方案。
JavaScript 继承基础概念
在深入探讨 JavaScript 继承机制之前,需要先明确几个基础概念。
父类:指被其他类继承的原始类。
子类:指通过继承关系从父类派生出来的类。
超类:通常作为父类的同义词使用。
抽象类:一般不用于直接实例化,主要作用是为其他类提供继承基础。
基类:指专门设计供其他类继承的类。
派生类:指由基类继承而来的类。
JavaScript 继承的五种主要方式
在 JavaScript 中,对象继承通常可以通过以下五种方式实现:
1. 对象冒充
2. 使用 call() 方法
3. 使用 apply() 方法
4. 原型链
5. 混合模式
对象冒充实现继承
A. 对象冒充
所谓对象冒充,是指新类通过调用旧类(必须为构造函数形式)来模拟父类行为,从而实现继承目的。
示例 1
代码如下:
function people(name,sex,age){ //使用构造函数方式
this.name=name;
this.sex=sex;
this.age=age;
this.say=function(){
alert("My name is "+this.name);
};
this.doing=function(){
alert("I am speaking");
};
}
var Marry=new people("Marry","Woman","23");
Marry.say();
Marry.doing();
function white_people(name,sex,age){
this.inherit=people;
this.inherit(name,sex,age);
delete this.inherit;
this.area=function(){
alert("I am in Europe");
}
}
var Tom=new white_people("Tom","man","21");
Tom.say();
Tom.area();
alert(Tom.age); 上述示例中,people 作为 white_people 的基类。请注意这种通过对象冒充实现继承的标准格式。
this.inherit=people; //冒充
this.inherit(name,sex,age); //继承
delete this.inherit; //删除继承
所有新增属性和方法必须在删除继承引用后定义,以避免覆盖父类原有的属性和方法。
此外,对象冒充支持多继承。
示例 2
代码如下:
function worker(pay,work){
this.pay=pay;
this.work=work;
}
function city_worker(name,sex,age,pay,work){
this.inherit=people;
this.inherit(name,sex,age);
delete this.inherit;
this.inherit=worker;
this.inherit(pay,work);
delete this.inherit;
}
var Jerry=new city_worker("Jerry","man","21","$1000","coder");
Jerry.say();
alert(Jerry.work); 对象冒充的一个不足之处在于:在实现多继承时,如果基类存在同名属性或方法,后续继承的类将覆盖前面的定义。
使用 call() 方法实现继承
B. call() 方式
这仅是对对象冒充的一种函数封装。无需编写繁琐的三行代码,只需使用以下语句即可:
基类.call(对象,参数列表)
示例 1
代码如下:
function farmer(name,sex,age,pay,work){
people.call(this,name,sex,age);
worker.call(this,pay,work);
}
var Nicholas=new farmer("Nicholas","man","27","$3000","irrigator");
Nicholas.say();
alert(Nicholas.pay); 同样,call() 方法也存在同名属性和方法覆盖的问题。
使用 apply() 方法实现继承
C. apply() 方式
与 call() 类似,apply() 也是对象冒充的一种封装函数。其语法格式为:
基类.apply(对象,参数数组);
示例 1
代码如下:
function white_collar(name,sex,age,pay,work){
people.apply(this,new Array(name,sex,age));
worker.apply(this,[pay,work]);
}
var Jiessie=new white_collar("Jiessie","woman","26","$2500","editor");
Jiessie.say();
alert(Jiessie.work); 同样,apply() 方法也存在同名属性和方法覆盖的问题。
原型链继承机制
D. 原型链
前三种方式均基于构造函数实现继承,对应地,基于原型函数的继承方式称为原型链。
示例 1
代码如下:
function blue_collar(){
}
blue_collar.prototype.name="Jean";
blue_collar.prototype.age="33";
blue_collar.prototype.say=function(){
alert("my name is "+ this.name);
};
function city_blue_collar(){
}
city_blue_collar.prototype=new blue_collar();
var jj=new city_blue_collar;
jj.say(); 原型链也存在局限性:无法传递参数。此外,由于原型链机制的原因,它不支持多继承。
混合模式继承最佳实践
E. 混合模式
使用构造函数来定义类的属性,并通过 call() 或 apply() 实现属性继承。
使用原型方式定义方法,并通过原型链实现方法继承。
示例 1
代码如下:
function beauty(name,age){
this.name=name;
this.age=age;
}
beauty.prototype.say=function(){
alert("小女叫"+this.name);
};
function china_beauty(name,age,area){
beauty.call(this,name,age);
this.area=area;
}
china_beauty.prototype=new beauty();
china_beauty.prototype.from=function(){
alert("我来自"+this.area);
};
var diaochan=new china_beauty("貂禅","16","临洮");
diaochan.say();
diaochan.from();
alert(diaochan.age);