JavaScript继承

由于JavaScript语言特性,它的继承类的继承方式是通过原型配合构造函数完成的,即使是ES6中出现的所谓的class和extends关键字,也仅仅是一种语法糖而已!

Quick Start

es5的继承

es5中属性的继续通过子类调用父类的构造函数(一般通过call的方式),方法的继承通过原型(子类的prototype指向父类的实例)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 父类
function Feather(name, age){
this.name = name;
this.age = age;
}
// 在原型上扩展方法。(作为构造函数时,属性一般作为每一个实例所特有的,方法作为所以实例所共有的,所以属性的初始化放在构造函数中,方法都放在原型上,因为原型对象上的方法会被所有实例所共享)
Feather.prototype.sayHello = function(){
console.log("大家好,我叫" + this.name);
}
// 子类
function Son(name, age, score){
Feather.call(this, name, age);//call的目的就是调用父类的构造函数,并使得父类中的this指向子类实例,从而对属性进行赋值(属性的继承)
this.score = score;
}

Son.prototype = new Feather();//子类的原型指向父类的实例(一个构造函数的原型是可以直接指向一个对象的)
Son.prototype.constructor = Son;//这一步很关键
Son.prototype.study = function(){
console.log(this.name + "在学习!");
}

const f = new Feather("老王", 50);
const s = new Son("小王", 20, 90);

console.log(f);
console.log(s);
f.sayHello();//sayHello本来是父类的原型方法,所以父类的实例自然可以直接使用
s.sayHello();//子类的原型上虽然没有sayHello方法,但它直接继承了父类的方法,所以子类的实例自然可以调用这个方法。
s.study();//子类独有的方法,其实例可以直接使用。

显然子类的原型上没有sayHello方法,但子类的实例却能直接调用父类原型上的方法

es6的继承

es6提出了class、extends关键字,写起来更加的方便简洁,更像传统面向对象语言(比如Java、C++、Python等)的语法,但这也仅仅是一种语法糖而已,并没有改变其基于原型的本质。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Feather {
constructor(name, age){
this.name = name;
this.age = age;
}
sayHello(){
console.log("我是" + this.name + ",我" + this.age + "岁了。");
}
}
class Son extends Feather{
constructor(name, age, score){
super(name, age);
this.score = score;
}
study(){
console.log(this.name + "在学习。");
}
}

const f = new Feather("老李", 40);
const s = new Son("小李", 10, 93);

console.log(f);
console.log(s);
f.sayHello();//sayHello本来是父类的共有方法,所以父类的实例自然可以直接使用
s.sayHello();//子类虽然没有sayHello共有方法,但它直接继承了父类的方法,所以子类的实例自然可以调用这个方法。
s.study();//子类独有的方法,其实例可以直接使用。

基于ES6的继承

总结

ES6的class加extend是继承方式本质仍然是ES5的原型方式,只是看起来更加简洁方便,而且更贴切传统面向对象语言的特点。还有就是ES5中继承方式有一个点必须注意:子类的原型由于改成了父类的一个实例,那么子类的原型的construct也就自然随之指向了父类的构造函数,这是不符合规范的(这个时候对子类原型添加的方法会影响父类)。所以必须进行矫正,让子类原型的construct从新指向子类自己的构造函数:Son.prototype.constructor = Son;在ES6这种语法糖的情况下就不需要考虑这么多细节了。这也是语法糖的一个特点:写法更加简单,但本质却没有改变。至于ES5中用到的call方法和ES6中用到的super方法要先理解new关键字执行背后的原理了!!


JavaScript继承
https://zbdev.online/2023/02/22/JavaScript继承/
作者
zzb
发布于
2023年2月22日
许可协议