# 继承
记录几个继承方法
# 原型链继承
function Car () {
this.name = "car";
}
Car.prototype.sayName = function () {
console.log(this.name);
}
function BenTian() { }
BenTian.prototype = new Car();
var bentian = new BenTian();
bentian.sayName();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 基于原型链的继承,这样引用类型的值会被所有的实例所共享。
- 在创建子类的实例的时候,不能够在不影响其他实例的情况下,传参数(super)
# 使用构造函数继承
function Car () {
this.name = "car";
this.say = function () {
console.log(this.name);
}
}
Car.prototype.sayName = function () {
console.log(this.name);
}
function BenTian() {
Car.call(this);
}
function FengTian() {
Car.call(this);
}
var bentian = new BenTian();
bentian.name = 'bentian';
bentian.say(); // bentian
// bentian.sayName(); // Uncaught TypeError: bentian.sayName is not a function
var bentian = new FengTian();
bentian.say(); // car
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
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
这种方式的继承的缺点也是很明显,虽然解决了原型链继承的问题,但是方法都必须在constructor中定义,函数并不能被复用,在创建实例的时候都会被创建一遍。
# 组合继承(伪经典继承)
function Car (name) {
this.name = name;
}
Car.prototype.sayName = function () {
console.log(this.name);
}
function Ri(name, color) {
Car.call(this, name);
this.color = color;
}
Ri.prototype = new Car();
Ri.prototype.constructor = Car;
var bentian = new Ri("bentian", "red");
var fengtian = new Ri("fengtian", "black");
console.log(bentian.name) // bentian
console.log(bentian.color) // red
console.log(fengtian.name) // fengtian
console.log(fengtian.color) // black
bentian.sayName(); // bentian
fengtian.sayName(); // fengtian
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
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
这种继承方式解决了原型链继承和构造函数继承的弊端,也是成功的继承了父类,但是这种继承方式本身也是存在着一些问题,比如多次调用了父类的constructor
# 原型式继承
var car = {
name: "car",
color: ['red', 'blue', 'black']
}
var car1 = Object.create(car);
car1.__proto__ === car;
var car2 = Object.create(car);
car2.__proto__ === car;
car1.name = "bentian";
car2.name = "fengtian";
car1.color.push('white')
console.log(car2.color) // ["red", "blue", "black", "white"]
// 引申
function createObj(o) {
function fn() {};
fn.prototype = o;
return new fn();
}
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
由此可见,原型式继承并不会重新创建引用类型的值,引用类型的值会被所有的实例共享。
如果理解不了,那你需要更多的去了解按值传递和按址(引用)传递的区别了
# 寄生式继承
function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () {
console.log('zhangsan');
}
return clone;
}
1
2
3
4
5
6
7
2
3
4
5
6
7
寄生式继承,和使用构造函数模式一样,都会在创建实例的时候重新创建父类。(也就是相当于复制出来一份 然后基于这个复制项来创建。 这样来保证两两互不干预)
# 寄生组合式继承
function inheritPrototype(Child, Parent) {
var prototype = Object.create(Parent.prototype);
prototype.constructor = Child;
Child.prototype = prototype;
}
function Car (name) {
this.name = name;
}
Car.prototype.sayName = function () {
console.log(this.name);
}
function Ri(name, color) {
// 传值
Car.call(this, name);
this.color = color;
}
inheritPrototype(Ri, Car);
var bentian = new Ri("bentian", "red");
var fengtian = new Ri("fengtian", "black");
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
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
保证了原型链链路的正确性,没有多余的属性等优点,所以最为理想的ES5继承
# 组合式寄生式继承 简约版
function Car (name) {
this.name = name;
}
Car.prototype.sayName = function () {
console.log(this.name);
}
function Ri(name, color) {
Car.call(this, name);
this.color = color;
}
Ri.prototype = Object.create(Car.prototype, {
constructor: {
value: Ri
}
})
var bentian = new Ri("bentian", "red");
var fengtian = new Ri("fengtian", "black");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
巧妙的利用了Object.create的第二个参数,实现修改原型的constructor的值。
# ES6继承
class Car {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
class BenTian extends Car {
constructor(name, color) {
super(name);
this.color = color;
}
sayName() {
//继承父类方法
super.sayName()
// 子类自己的
console.log(this.color);
}
}
const bentian = new BenTian('bentian', 'red');
console.log(bentian.name); // bentian
console.log(bentian.color); // red
bentian.sayName(); // bentian red
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
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
- 在语法糖下代码量明显减少
- ES5的继承是首先在子类中创建自己的this指向,最后将方法添加到this中,例如:
BenTian.prototype = new Car() || Car.apply(this) || Car.call(this)
1
- ES6继承,子类使用super关键字先创建父类实例的this,最后在子类中修改自己的this
# 致谢
感谢大家阅读我的文章,如果对我感兴趣可以点击页面右上角,帮我点个star。
作者:前端小然子
链接: https://xiaoranzife.com/guide/jichu/%E7%BB%A7%E6%89%BF.html
来源:前端小然子的博客
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
← 浅谈this指向 手写 new 操作符 →