Skip to content

ES5/ES6 的继承除了写法以外还有什么区别? #15

Description

@lvwxx

ES6 继承

ES6 通过 class 关键字实现类,类与类之间通过 extends 关键字实现继承。

class Super {
  constructor(x,y) {
    this.x = x
    this.y = y
  }
  print() {
    console.log(this.x, this.y)
  }
}

class Sub extends Super {
  constructor(x,y) {
    super(x,y)
  }
}

const sub = new Sub(1,2)
sub.print() // 1,2

上面代码中,子类 Sub 的 constructor 方法中出现了 super 关键字, 它在这里表示父类构造函数,用来新建父类的 this 对象

子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错。这是因为子类自己的 this 对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用 super 方法,子类就得不到 this 对象。

ES5 继承

ES5 没有 class关键字,通过修改原型链实现继承

function Super() {
  this.name = 'super'
}
Super.prototype.print = function() {
  console.log(this.name, this.x, this.y)
}

function Sub(x,y) {
  this.x = x
  this.y = y
}

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

const sub = new Sub(1, 2)
sub.print() // super 1 2

当试图访问一个对象的属性或者方法时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

上面的代码中, 子类 Sub 的 prototype 属性指向了 Super 的实例,也就是把 Sub 的原型指向了 Super 的一个实例, 每个实例对象内部都有一个 proto 属性,指向构造函数的原型对象,这样,通过 proto 属性的指向,形成了原型链,用代码将上述关系可以表示为:

Sub.prototype.__proto__ === Super.prototype  // true
sub.__proto__ === Sub.prototype  // true

当我们调用 sub 实例的 print 方法时,首先在 sub 对象自身上查找,发现没有这个方法,就回去 sub 的构造函数原型上去查找,也就是看 Sub.prototype 对象是否存在 print 方法, 发现也没有,最后再去查询 Sub.prototype 的原型,即 Super.prototype上调用这个方法。

总结

  • Class 声明变量会进入暂时性死区, 也就是必须先声明,再使用。
  • Class 通过 extends 关键字实现继承。 ES5 通过修改原型链实现继承
  • Class 内部定义的所有方法都不可枚举,这在 ES5 中默认是可枚举的
  • Class 内部默认使用严格模式
  • 最重要的一点不同是: ES5 是先创建子类实例对象的this,然后将父类方法赋到这个this上。Class 是先在子类构造函数中用 super 创建父类实例的 this,再在构造函数中进行修改它,这个差别使得 ES6 可以继承内置对象。。
  • Class 的子类,通过 proto 属性可以直接访问到父类 如:
function Super() {
  this.name = 'super'
}
Super.prototype.print = function() {
  console.log(this.name, this.x, this.y)
}

function Sub(x,y) {
  this.x = x
  this.y = y
}

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

const sub = new Sub(1, 2)
Sub.__proto__ === Function.prototype // true

class Super {}
class Sub extends Super {}
Sub.__proto__ === Super // true

Metadata

Metadata

Assignees

No one assigned

    Labels

    basicJavaScript basic knowledge must konwquestionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions