【前端100问】Q7:ES5/ES6 的继承除了写法以外还有什么区别?

写在前面

此系列来源于开源项目:前端 100 问:能搞懂 80%的请把简历给我
为了备战 2021 春招
每天一题,督促自己
从多方面多角度总结答案,丰富知识
ES5/ES6 的继承除了写法以外还有什么区别?

正文回答

// ES6
class Super {}
class Sub extends Super {}

const sub = new Sub();

Sub.__proto__ === Super;

子类可以直接通过 __proto__ 寻址到父类。

// ES5
function Super() {}
function Sub() {}

Sub.prototype = new Super();
Sub.prototype.constructor = Sub;

var sub = new Sub();

Sub.__proto__ === Function.prototype;

而通过 ES5 的方式,Sub.__proto__ === Function.prototype

ES5 和 ES6 子类 this 生成顺序不同。

ES5 的继承先生成了子类实例,再调用父类的构造函数修饰子类实例

ES6 的继承先生成父类实例,再调用子类的构造函数修饰父类实例。

这个差别使得 ES6 可以继承内置对象。

function MyES5Array() {
  Array.call(this, arguments);
}

// it's useless
const arrayES5 = new MyES5Array(3); // arrayES5: MyES5Array {}

class MyES6Array extends Array {}

// it's ok
const arrayES6 = new MyES6Array(3); // arrayES6: MyES6Array(3) []

因为 this 生成顺序不同,所以需要在 constructor 中,需要使用 super()

扩展知识点

ES5 最常见的两种继承:原型链继承、构造函数继承

  1. 原型链继承
// 定义父类
function Parent(name) {
  this.name = name;
}

Parent.prototype.getName = function () {
  return this.name;
};

// 定义子类
function Children() {
  this.age = 24;
}

// 通过Children的prototype属性和Parent进行关联继承

Children.prototype = new Parent("陈先生");

// Children.prototype.constructor === Parent.prototype.constructor = Parent

var test = new Children();

// test.constructor === Children.prototype.constructor === Parent

test.age; // 24
test.getName(); // 陈先生

我们可以发现,整个继承过程,都是通过原型链之间的指向进行委托关联,直到最后形成了”由构造函数所构造“的结局。

  1. 构造函数继承
// 定义父类
function Parent(value) {
  this.language = ["javascript", "react", "node.js"];
  this.value = value;
}

// 定义子类
function Children() {
  Parent.apply(this, arguments);
}

const test = new Children(666);

test.language; // ['javascript', 'react', 'node.js']
test.value; // 666

构造继承关键在于,通过在子类的内部调用父类,即通过使用 apply()call()方法可以在将来新创建的对象上获取父类的成员和方法。

  1. ES6 的继承
// 定义父类
class Father {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  show() {
    console.log(`我叫:${this.name}, 今年${this.age}岁`);
  }
}

// 通过extends关键字实现继承
class Son extends Father {}

let son = new Son("陈先生", 3000);

son.show(); // 我叫陈先生 今年3000岁

ES6 中新增了 class 关键字来定义类,通过保留的关键字 extends 实现了继承。实际上这些关键字只是一些语法糖,底层实现还是通过【原型链之间的委托关联】关系实现继承。

区别于 ES5 的继承,ES6 的继承实现在于使用 super 关键字调用父类,反观 ES5 是通过 call 或者 apply 回调方法调用父类。

你可能感兴趣的:(【前端100问】Q7:ES5/ES6 的继承除了写法以外还有什么区别?)