📜  继承javascript(1)

📅  最后修改于: 2023-12-03 15:11:41.750000             🧑  作者: Mango

继承JavaScript

继承是面向对象编程的一个重要概念。在JavaScript中,继承的实现方式与传统面向对象编程语言略有不同。本文将介绍如何在JavaScript中进行继承,包括原型链、构造函数绑定和组合继承三种实现方式。

原型链

在JavaScript中,每个对象都有一个原型对象。原型对象具有一个指向另一个原型对象的指针,构成了一个原型链。

对象可以通过该原型链来继承另一个对象的属性和方法。假设我们有一个父类

function Parent() {
    this.name = 'parent';
}

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

我们可以使用new操作符创建一个子类实例,并将原型链指向父类的原型对象:

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

var child = new Child();
child.sayName(); // parent

这里我们将Child的原型对象指向了一个新创建的Parent实例,那么Child实例就可以通过原型链继承Parent的属性和方法。

值得注意的是,通过原型链实现继承时,如果在子类实例中修改属性和方法,其实是在子类实例中添加了一个同名属性或方法,而不是修改父类中的属性或方法。这会影响到所有子类实例和当前实例原型链上的对象。

child.name = 'child';
child.sayName(); // child

var child2 = new Child();
child2.sayName(); // parent

我们可以看到,修改了child实例的name后,虽然依然继承自父类,但是输出的name已经不是从父类继承而来了。

构造函数绑定

通过原型链实现继承有一个致命缺陷:所有子类实例都会共享父类属性和方法。这是由于原型对象是共享的。

function Parent() {
    this.colors = ['red', 'green', 'blue'];
}

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

var child1 = new Child();
child1.colors.push('purple');
var child2 = new Child();
console.log(child2.colors); // ['red', 'green', 'blue', 'purple']

我们在Child的实例化对象中修改了共享的数组,导致其它实例也会因此受影响。

为了解决这个问题,我们可以通过构造函数绑定实现继承。这种方式会在子类实例内部创建一个新的父类实例,而不是将父类的原型对象赋值给子类原型对象。

function Parent() {
    this.colors = ['red', 'green', 'blue'];
}

function Child() {
    Parent.call(this);
}

var child1 = new Child();
child1.colors.push('purple');
var child2 = new Child();
console.log(child2.colors); // ['red', 'green', 'blue']

在子类构造函数中使用callapply方法,可以将父类的属性绑定在子类的实例上,实现继承。

组合继承

上述两种方式各有优缺点,组合继承是将它们合并在一起的最佳方式。

组合继承首先通过构造函数绑定创建子类实例的属性,在子类原型对象上通过原型链继承父类的方法。

function Parent(name) {
    this.name = name;
    this.colors = ['red', 'green', 'blue'];
}

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

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

Child.prototype = new Parent();
Child.prototype.constructor = Child;

var child1 = new Child('child1');
child1.sayName(); // child1
child1.colors.push('purple');
var child2 = new Child('child2');
console.log(child2.colors); // ['red', 'green', 'blue']

在这种方式下,每个子类实例都拥有父类实例的所有属性和方法,而且各自拥有独立的属性和方法。

结论

JavaScript中的继承通过原型链、构造函数绑定和组合继承等方式实现。掌握这些继承方式可以有效地提高代码的复用性和可维护性。