欢迎访问宙启技术站
智能推送

JS如何实现继承?

发布时间:2023-05-16 04:45:36

在JavaScript中,实现继承有多种方式,包括原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承和寄生组合式继承等。下面将依次介绍每种继承方式的实现过程及其优缺点。

1. 原型链继承

原型链继承是将子类构造函数的原型对象指向父类构造函数的实例,从而实现继承。实现过程如下:

function Parent() {
    this.name = 'parent';
}
Parent.prototype.sayName = function () {
    console.log(this.name);
};

function Child() {
    this.age = 18;
}
Child.prototype = new Parent();

var child = new Child();
child.sayName(); // 'parent'
console.log(child.age); // 18

在上述代码中,子类Child的构造函数继承了父类Parent的构造函数,并将其原型对象指向了父类实例。缺点是如果父类中有引用类型的属性,那么子类实例间对于该属性的修改将会互相影响,因为实例共享同一个引用类型属性;另外无法向父类构造函数传值,即无法向父类构造函数传入参数。

2. 构造函数继承

构造函数继承是通过在子类构造函数内部执行父类构造函数,并使用call()或者apply()方法调用,从而实现继承。实现过程如下:

function Parent(name) {
    this.name = name;
}
Parent.prototype.sayName = function () {
    console.log(this.name);
};

function Child(name, age) {
    Parent.call(this, name);
    this.age = age;
}

var child = new Child('child', 18);
child.sayName(); // 'child'
console.log(child.age); // 18

在上述代码中,子类Child中通过调用父类Parent并传入参数,从而实现了属性的继承。与原型链继承相比,构造函数继承避免了父类引用类型属性的共享问题。但是每次创建子类实例时都会执行一遍父类构造函数,导致性能上的问题。此外,子类实例无法访问到父类的原型对象,无法复用父类原型对象中的方法。

3. 组合继承

组合继承是将原型链继承和构造函数继承结合起来,从而既继承了父类原型对象中的方法,又继承了父类构造函数中的属性。实现过程如下:

function Parent(name) {
    this.name = name;
}
Parent.prototype.sayName = function () {
    console.log(this.name);
};

function Child(name, age) {
    Parent.call(this, name);
    this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;

var child = new Child('child', 18);
child.sayName(); // 'child'
console.log(child.age); // 18

在上述代码中,首先通过构造函数继承实现了属性的继承,然后使用原型链继承实现了方法的继承,并重新指定了子类的构造函数。组合继承是目前最常用的继承方式之一,既避免了原型链继承的引用类型属性共享和构造函数继承的性能问题,又继承了父类构造函数中的属性和原型对象中的方法。

4. 原型式继承

原型式继承是通过Object.create()方法创建一个新对象,并将其原型对象指向父类对象,从而实现继承。实现过程如下:

var parent = {
    name: 'parent',
    sayName: function () {
        console.log(this.name);
    }
};

var child = Object.create(parent);
child.name = 'child';
child.sayName(); // 'child'

在上述代码中,使用Object.create()方法创建了一个新对象child,并将其原型对象指向了父类对象parent。原型式继承与原型链继承类似,会产生引用类型属性共享的问题,但与原型链继承不同的是,原型式继承可以通过传入第二个参数,来增强子类对象的属性。另外,原型式继承与构造函数继承不同,可以在不用创建构造函数的情况下实现继承。

5. 寄生式继承

寄生式继承是在原型式继承的基础上,需要创建一个函数,包装原型继承返回了一个新的对象,不同于原型继承的是,寄生式继承是重新定制继承对象的一些属性和方法的。实现过程如下:

function createAnother(original) {
    var clone = Object.create(original);
    clone.sayName = function () {
        console.log(this.name);
    };
    return clone;
}

var parent = {
    name: 'parent'
};

var child = createAnother(parent);
child.sayName(); // 'parent'

在上述代码中,通过createAnother()函数创建了一个新对象child,继承了父类对象parent,并重写了sayName()方法。寄生式继承与构造函数继承类似,可以在创建新对象时增强属性和方法,但也存在和构造函数继承相同的问题,会创建出不必要的函数对象。

6. 寄生组合式继承

寄生组合式继承是在组合继承的基础上进行优化。对于一个父类构造函数,使用Object.create()方法创建一个新的原型对象,再将该原型对象赋值给子类构造函数的原型对象,从而实现继承。实现过程如下:

function Parent(name) {
    this.name = name;
}
Parent.prototype.sayName = function () {
    console.log(this.name);
};

function Child(name, age) {
    Parent.call(this, name);
    this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

var child = new Child('child', 18);
child.sayName(); // 'child'
console.log(child.age); // 18

在上述代码中,首先通过构造函数继承实现了属性的继承,然后使用Object.create()方法创建一个新的原型对象,再将该原型对象指定给子类构造函数的原型对象。寄生组合式继承继承了父类构造函数中的属性和原型对象中的方法,同时避免了原型链继承的引用类型属性共享和构造函数继承的性能问题。寄生组合式继承是目前最常用的继承方式之一。

总结:

以上介绍的继承方式各有特点,可依据实际需求选择。其中,对于开发大型应用程序,建议使用组合继承或寄生组合式继承。