# JavaScript 进阶之继承的多种方式
# 原型继承
原型链继承是让子类的原型指向父类的一个实例,让子类和父类建立原型链接的机制,子类的实例调取父类原型上的方法,都是基于原型链的查找机制完成的。
function Parent (name) {
this.name = name;
this.age = 18;
}
Parent.prototype.getName = function () {
console.log('My name is ' + this.name);
}
function Child () {
}
Child.prototype = new Parent();
var child = new Child();
console.log(child.name); // undefined
console.log(child.age); // 18
child.getName(); // "My name is undefined"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Child.prototype = new Parent();,Parent 的实例本身具备父类 Parent 的私有属性和公有方法,子类 Child 的原型指向Parent 的实例,那么子类 Child 的实例就可以找到这些属性和方法了。
这种继承方式存在的问题:
- 父类实例私有的属性和公有的属性都变为子类实例的公有属性。
- 在创建 Child 的实例时,不能向 Parent 传参。
# 构造函数继承
构造函数继承就是把父类Parent作为普通函数执行,让Parent中的this变为Child的实例,相当于给Child的实例增加一些属性和方法。
function Parent (name) {
this.name = name;
}
Parent.prototype.getName = function () {
console.log('My name is ' + this.name);
}
function Child (name) {
Parent.call(this, name);
}
var child = new Child('lilei');
console.log(child.name); // "lilei"
console.log(child.getName()); // TypeError: child.getName is not a function
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
这种继承方式避免了父类私有属性变为子类实例公有属性的情况,同时解决了 Child 向 Parent 传参的问题。
弊端就是由于把父类Parent当做普通函数执行,仅仅是把父类中的私有属性变为子类实例的私有属性而已,父类原型上的公有属性和方法并没有继承给子类及其实例。
# 寄生组合式继承
function Parent (name) {
this.name = name;
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name, age) {
Parent.call(this, name);
this.age = age;
}
// 增加了一级原型链(__proto__),相当于隔离了Child和Parent
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
var child = new Child('lilei', 18);
console.log(child.name); // "lilei"
console.log(child.age); // 18
child.getName(); // "My name is lilei"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
这种继承方式弥补了原型继承和构造函数继承的弊端,Parent 的私有属性变为 Child 的私有属性,Parent 的公有变为 Child 的公有属性。
Child.prototype = new Parent(); 这种方式创建的父类的实例虽然指向父类的原型,但是实例中存放了父类的私有属性,而这些不必要的、多余的属性变为子类的公有属性,
Child.prototype = Object.create(Parent.prototype); 这种方式创建了一个没有任何私有属性的对象,指向父类的原型,这样子类的公有属性中就不会存在父类的私有属性了。
# ES6 继承
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
getName() {
return this.name
}
}
// Student类继承Person类
class Student extends Person {
constructor(name, age, gender, classes) {
super(name, age); // 表示构造函数的继承
this.gender = gender;
this.classes = classes;
}
getGender() {
return this.gender;
}
}
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
继承思想沿用寄生组合式继承,ES6 中创建类是有自己标准语法的(这种语法创建出来的类只能NEW执行,不能当做普通函数执行)。