Skip to the content.

ES5 和 ES6分别如何实现继承?

前言

继承这个概念在面向对象编程思想里面十分重要,也是面试必考的考点之一。 javascript的继承主要是依托其原型与原型链的概念来实现的。

ECMAscript将原型链作为实现继承的主要方法。

对原型与原型链还不是很了解的同学可以看下原型与原型链,你真的学废了吗?

先来看看ES6的实现

ES6提供了Class关键字来实现类的定义,Class 可以通过extends关键字实现继承,让子类继承父类的属性和方法。

这句话概括性很强,具体的就没要展开了,实现的细节部分后面会单独在我的专栏【重学ES6】系列中重点剖析,感兴趣的可以关注下,共同学习成长。

咱们重点讲一下ES5的三种常用的实现方式。

ES5实现的三种方式

1. 原型链继承

原型链继承的原理很简单,直接让子类的原型对象指向父类实例,当子类实例找不到对应的属性和方法时,就会往它的原型对象,也就是父类实例上找,从而实现对父类的属性和方法的继承

function Person() {
    this.name = 'Back_kk';
}
Person.prototype.getName = function() {
    return this.name;
}
function Student() {}
Student.prototype = new Person();
// 根据原型链的规则,顺便绑定一下constructor, 这一步不影响继承, 只是在用到constructor时会需要
// 原型的实例等于自身
Student.prototype.constructor = Student;

const student = new Student();
console.log(student.name); // Back_kk
console.log(student.getName()); // Back_kk

缺陷

  1. 由于所有Student实例原型都指向同一个Person实例, 因此对某个Student实例的来自父类的引用类型变量修改会影响所有的Student实例

例如:

function Person() {
    this.obj = {
        name: 'Back_kk',
        age: 18
    };
}
function Student() {}
Student.prototype = new Person();
// 根据原型链的规则,顺便绑定一下constructor, 这一步不影响继承, 只是在用到constructor时会需要
// 原型的实例等于自身
Student.prototype.constructor = Student;

const student1 = new Student();
student1.obj.name = '佩奇';
const student2 = new Student();
console.log(student2.obj.name); // 佩奇
  1. 在创建子类实例时无法向父类构造传参, 即没有实现super()的功能

    那么能不能实现super()功能呢?大家有兴趣可以思考下。

2. 构造函数继承

构造函数继承,即在子类的构造函数中执行父类的构造函数,并为其绑定子类的this,让父类的构造函数把成员属性和方法都挂到子类的this上去,这样既能避免实例之间共享一个原型实例,又能向父类构造方法传参。

function Person(name) {
    this.name = name
}
Person.prototype.getName = function() {
    return this.name;
}
function Student() {
    Person.apply(this, arguments);
}

const student = new Student('Back_kk');
console.log(student.name); // Back_kk

缺陷

3. 组合式继承

组合是继承结合了原型集成和构造函数继承的特点。

function Person(name) {
    this.name = name;
}
Person.prototype.getName = function() {
    return this.name;
}
function Student() {
    // 构造函数继承
    Person.apply(this, arguments)
}
// 原型式继承
Student.prototype = new Person();

// 原型的实例等于自身
Student.prototype.constructor = Student;

const student = new Student('Back_kk');
console.log(student.name); // Back_kk
console.log(student.getName()); // Back_kk

缺陷

image.png

“原型中会存在两份相同的属性和方法”,这句没有很理解,哪位大佬可以帮忙解答下?

4. 寄生式组合继承

解决构造函数被执行两次的问题, 我们将指向父类实例改为指向父类原型, 减去一次构造函数的执行。 ```js function Person(name) { this.name = name; } Person.prototype.getName = function() { return this.name; } function Student() { // 构造函数继承 Person.apply(this, arguments) } // 原型式继承 // Student.prototype = new Person(); Student.prototype = Object.create(Person.prototype);

// 原型的实例等于自身 Student.prototype.constructor = Student;

const student = new Student(‘Back_kk’); console.log(student.name); // Back_kk console.log(student.getName()); // Back_kk ```

关于Object.create()在原型链上的指向问题可以康康 这里

这是目前ES5中比较成熟的继承方式了。

总结

预告

相关推荐

参考

https://www.cnblogs.com/0314dxj/p/13886141.html