JavaScript中实现继承功能通常有几种方法,如原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承。这些方法各有优缺点,寄生组合式继承是一种较为完善的继承方式,它避免了原型链和构造函数的一些问题。以下是一个通过寄生组合式继承实现inherit
方法的示例:
function inherit(Child, Parent) {
var prototype = Object.create(Parent.prototype); // 创建对象,创建父类原型的一个副本
prototype.constructor = Child; // 增强对象,强化构造函数的原型
Child.prototype = prototype; // 指定对象,将新创建的对象(即副本)赋给子类的原型
}
这个inherit
方法通过Object.create
创建了父类原型的一个副本,然后修正了副本的构造函数指向子类,最后将这个副本赋给子类原型,从而完成继承。这种方法相比于其他继承方式减少了不必要的父类实例属性,仅仅涉及原型对象,因此性能更优,并且更加优雅。
一、原型链继承
原型链继承是最基本的继承方式,在JavaScript中通过原型对象prototype链实现,子类的原型是父类的一个实例。
function Parent() {
this.parentProperty = true;
}
Parent.prototype.getParentProperty = function() {
return this.parentProperty;
};
function Child() {
this.childProperty = false;
}
// 继承Parent
Child.prototype = new Parent();
但是,这种方法存在几个问题:它会将父类的所有属性继承到子类上,包括引用类型的属性,这可能会导致子类实例间相互影响。
二、构造函数继承
构造函数继承使用父类的构造函数来增强子类的实例,即在子类的构造函数中调用父类的构造函数。
function Parent(name) {
this.name = name;
}
function Child(name) {
Parent.call(this, name);
}
通过使用.call()
或.apply()
方法,构造函数继承允许子类得到父类的属性和方法。但此方法无法继承父类原型上的属性和方法。
三、组合继承
组合继承结合了原型链继承和构造函数继承的优点,既继承了父类的原型上的属性和方法,也继承了父类实例上的属性。
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.sayName = function() {
return this.name;
};
function Child(name, age) {
Parent.call(this, name); // 继承实例属性,第一次调用Parent()
this.age = age;
}
Child.prototype = new Parent(); // 继承父类方法,第二次调用Parent()
Child.prototype.constructor = Child;
Child.prototype.sayAge = function() {
return this.age;
};
组合继承解决了原型链和构造函数继承的问题,但是它会调用两次父类构造函数,产生不必要的性能开销。
四、原型式继承
原型式继承是在原型链继承基础上,使用一个函数包装一个已有的对象作为新对象的原型。
function createObj(o) {
function F(){}
F.prototype = o;
return new F();
}
这种方式利用了空函数F
作为中介,避免了直接使用已有对象作为原型的弊端,但由于共享了原型,则存在引用类型共享的问题。
五、寄生式继承
寄生式继承通过创建一个仅用于封装继承过程的函数,该函数在内部以某种方式增强对象,最后再像真的是它做了所有工作一样返回对象。
function createAnother(original) {
var clone = Object.create(original); // 通过调用函数创建一个新对象
clone.sayHi = function() { // 以某种方式来增强这个对象
console.log('hi');
};
return clone; // 返回这个对象
}
尽管解决了原型中包含引用类型值被所有实例共享的问题,但跟借用构造函数模式一样,每次创建对象都会创建一遍方法。
六、寄生组合式继承
寄生组合式继承是引用最广泛的继承方式,它通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
function inherit(Child, Parent) {
var prototype = Object.create(Parent.prototype);
prototype.constructor = Child;
Child.prototype = prototype;
}
该方法只调用了一次Parent
构造函数,并且避免了在Parent.prototype
上创建不必要的、多余的属性。与此同时,原型链还保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf。这个函数的高效率体现它是实现继承的最佳模式。
总结而言,寄生组合式继承是最理想的JavaScript继承方式,它解决了其他方法存在的继承缺点,并且能够正确地维护原型链,是实际应用中最为推荐的继承方法。
相关问答FAQs:
1. 如何在JavaScript中实现继承功能?
在JavaScript中,可以通过使用原型链或者ES6中的class来实现继承功能。使用原型链时,需要创建一个基类(父类)并在其原型对象上定义方法和属性,然后在子类的原型对象上通过Object.create()
方法创建新的对象,并将其原型设置为父类的实例,从而实现继承。使用class时,可以使用extends
关键字创建一个子类,并使用super
关键字调用父类的构造函数和方法,实现继承。
2. 什么是原型链继承?如何使用原型链继承实现继承功能?
在JavaScript中,原型链继承是一种实现继承的方式。每个对象都有一个原型对象,在创建对象时会将其原型对象指向其创建对象的构造函数的原型对象。当访问对象上的属性或方法时,如果对象本身没有该属性或方法,会通过原型链查找其原型对象,直到找到该属性或方法或者到达原型链的末尾为止。
要使用原型链继承实现继承功能,首先需要创建一个基类(父类)并在其原型对象上定义方法和属性。然后,在子类的原型对象上使用Object.create()
方法创建一个新的对象,并将其原型设置为父类的实例,从而实现继承父类的属性和方法。子类的原型对象会形成一个原型链,可以从父类的原型对象继承属性和方法。
3. 使用ES6中的class如何实现继承功能?
在ES6中,可以使用class关键字来创建类并实现继承功能。使用extends关键字可以创建一个子类,子类会继承父类的所有属性和方法。在子类的构造函数中,使用super关键字调用父类的构造函数,并可以传递参数给父类的构造函数。子类可以通过super关键字调用父类的方法。利用class和extends关键字,可以更直观和简洁地实现继承功能。