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
ES6 继承
ES6 通过 class 关键字实现类,类与类之间通过 extends 关键字实现继承。
上面代码中,子类 Sub 的 constructor 方法中出现了 super 关键字, 它在这里表示父类构造函数,用来新建父类的 this 对象
子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错。这是因为子类自己的 this 对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用 super 方法,子类就得不到 this 对象。
ES5 继承
ES5 没有 class关键字,通过修改原型链实现继承
当试图访问一个对象的属性或者方法时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
上面的代码中, 子类 Sub 的 prototype 属性指向了 Super 的实例,也就是把 Sub 的原型指向了 Super 的一个实例, 每个实例对象内部都有一个 proto 属性,指向构造函数的原型对象,这样,通过 proto 属性的指向,形成了原型链,用代码将上述关系可以表示为:
当我们调用 sub 实例的 print 方法时,首先在 sub 对象自身上查找,发现没有这个方法,就回去 sub 的构造函数原型上去查找,也就是看 Sub.prototype 对象是否存在 print 方法, 发现也没有,最后再去查询 Sub.prototype 的原型,即 Super.prototype上调用这个方法。
总结