js中的继承

74 阅读2分钟

在javascript中实现继承的方法有多种,常见的继承方式有原型链继承、借用构造函数实现继承、组合继承(原型链继承+借用构造函数继承)以及ES6中通过extends实现继承。继承的方式有多种,但是各有优缺点。下面详细介绍上文提到的几种继承方式。

1、原型链继承

function Father() {
    this.a = 1;
    this.b = 2;
}
function Son() { };
// 将Son构造函数的原型设置为Father构造函数的实例,使得Son的实例可以访问Father中的属性和原型上的属性方法
Son.prototype = new Father(); 
const son = new Son();
console.log(son.a); // 1

通过原型链实现了对象的继承,但是改继承方式不完美,有问题。实例之间不独立,共享Father中的属性(属性值为引用值的属性)。具体表现如下代码片段所示

function Father() {
    this.a = 1;
    this.b = 2;
    this.test = [1, 2, 3];
}
function Son() { };
Son.prototype = new Father(); 
const son1 = new Son();
// 因为son1自身并没有test属性,所以通过原型链寻找test,在Father上找到tests属性,并修改test属性
son1.test.push(4); 
// son2继承了Father的属性(此时Father的test属性已经被修改)
const son2 = new Son();
console.log(son1.test); // [1, 2, 3, 4]
console.log(son2.test); // [1, 2, 3, 4]

2、借用构造函数实现继承

利用原型实现的对象继承,实例之间存在者共享属性(属性值为引用值的属性)的问题。我们可以借用构造函数解决这个问题。具体实现如下代码所示:

function Father(a) {
    this.a = a
    this.test = [1, 2, 3];
}

function Son(a) {
    // 调用Father构造函数并更改father中的this指向为Son的实例。给son的实例添加和Father相同的属性
    Father.call(this, a);
}

const son1 = new Son(1);
son1.test = [1, 2, 3, 4]; 
const son2 = new Son(2);
console.log(son2.test); // [1, 2, 3] son2.test并没有改变和Father构造函数定义的是一样的。

虽然借用构造函数实现的对象继承解决了属性共享的问题。但是此继承方式却不能继承Father原型上的属性和方法。

3、组合继承

组合继承就是将原型链继承和借用构造函数继承两种方式结合的继承方式。根据具体的组合方式。组合继承又分为伪经典组合继承和寄生组合继承。

  • 伪经典继承
function Father() {
    this.name = 'test';
    this.arr = [1, 2];
}

Father.prototype.age = 12;

function Son() {
    Father.call(this);
}

Son.prototype = new Father(); 

const son = new Son();
son.arr.push(3);
const son1 = new Son();
console.log(son1); // { name: 'test',arr: (2) [1, 2] }

该组合继承方式之所以称之为伪经典组合继承是因为Father构造函数被执行了两次。消耗性能。

  • 寄生组合继承(经典继承)
function Father() {
    this.name = 'test';
    this.arr = [1, 2];
}

Father.prototype.age = 12;

function Son() {
    Father.call(this);
}
// 以下两句话也是圣杯模式继承的实现
Son.prototype = Object.create(Father.prototype);
Son.prototype.constructor = Son; // 重置Son.prototype.constructor为Son

const son = new Son();

4、ES6中的继承(extends)

class Father {
    constructor(name) {
        this.name = name;
    }
}

class Son extends Father {
    constructor(name) {
        super(name);
    }
}

const son = new Son('张三');

console.log(son); // {name: '张三'}

参考:www.imooc.com/article/201…