# ❓ES5/ES6 的继承除了写法以外还有什么区别?
# 继承差异:
ES5 的继承,实质是先创造子类的实例对象
this
,然后再将父类的方法添加到this
上面(Parent.apply(this)
)。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this
上面(所以必须先调用super
方法),然后再用子类的构造函数修改this。
ES5 实现之中,每一个对象都有
__proto__
属性,指向对应的构造函数的prototype
属性。 Class 作为构造函数的语法糖,同时有prototype
属性和__proto__
属性,因此同时存在两条继承链。- 子类的
__proto__
属性,表示构造函数的继承,总是指向父类。 - 子类
prototype
属性的__proto__
属性,表示方法的继承,总是指向父类的prototype
属性。
class A {} class B extends A {} B.__proto__ === A; // true B.prototype.__proto__ === A.prototype; // true
1
2
3
4
5
6- 子类的
除继承外的一些差异,我们的 🌰
// es5
function AnimalEs5(name) {
this.name = name;
}
AnimalEs5.prototype.getName = function() {
return this.name;
};
// es6
class AnimalEs6 {
constructor(name) {
this.name = name;
}
static getType() {
return "AnimalEs6";
}
getName() {
return this.name;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class
声明不会变量提升
new Foo(); // ReferenceError: Foo is not defined
class Foo {
1
2
3
2
3
上面代码中,Foo 类使用在前,定义在后,这样会报错,因为 ES6 不会把类的声明提升到代码头部。这种规定的原因也与继承有关,必须保证子类在父类之后定义。
class
必须使用new
调用,否则会报错
// es5 调用
AnimalEs5(); // it's ok
// es6 调用
AnimalEs6(); // Class constructor AnimalEs6 cannot be invoked without 'new'
1
2
3
4
5
2
3
4
5
class
的内部,默认就是严格模式
类和模块的内部,默认就是严格模式,所以不需要使用 use strict 指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式。
// 引用一个未声明的变量
function Bar() {
baz = 42; // it's ok
}
const bar = new Bar();
class Foo {
constructor() {
fol = 42; // ReferenceError: fol is not defined
}
}
const foo = new Foo();
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
class
内部所有定义的方法都是不可枚举的(non-enumerable)
// es5 调用
Object.keys(AnimalEs5.prototype); // [ 'getName' ]
Object.getOwnPropertyNames(AnimalEs5.prototype); // [ 'constructor', 'getName' ]
// es6调用
Object.keys(AnimalEs6.prototype); // []
Object.getOwnPropertyNames(AnimalEs6.prototype); // [ 'constructor', 'getName' ]
1
2
3
4
5
6
7
2
3
4
5
6
7
class
内声明的所有的方法(包括静态方法和实例方法)都没有原型对象 prototype 所以也没有 [[construct]],不能用new
来调用
const dog = new AnimalEs5();
const dogName = new dog.getName(); // it's ok
const es6Dog = new AnimalEs6();
const es6DogName = new es6Dog.getName(); // TypeError: es6Dog.getName is not a constructor
1
2
3
4
5
2
3
4
5
class
内部类名无法被重写
class AnimalEs6 {
constructor(name) {
this.name = name;
// AnimalEs6 = "AnimalEs6Change"; // TypeError: Assignment to constant variable.
// asd = "dad"; // ReferenceError: asd is not defined 严格模式
}
static getType() {
return "AnimalEs6";
}
getName() {
return this.name;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
如果大家有看 test🌰 的注意报错哦。