# 继承(一)
需要掌握吗?
- 面试题热门问题
- js基础重点
- 面向对象编程
- 主流框架使用广泛 reactjs、vuejs、angularjs、rxjs....
# 什么是js继承?
JavaScript继承是指一个对象通过从另一个对象(通常是父对象或基类)获取属性和方法的过程。在继承中,子类可以重写父类的方法,也可以增加新的方法和属性。这种方式可以使代码更加复用和灵活
# 继承方式有哪些?
1. 原型继承:通过原型链的方式,让新创建的对象可以访问到其他对象的属性和方法
概念: JavaScript中的原型继承是指对象通过原型链来获取属性和方法的过程。每个对象都有一个原型对象,它是一个引用类型,包含了一个指向父对象的引用,通过它可以在父对象中查找属性和方法。如果在当前对象中找不到某个属性或方法,就会沿着原型链向上查找,直到找到为止。
- eg.
# 1.原型链继承
// 定义一个基础对象
var base = {
name: 'base',
sayHello: function() {
console.log('Hello, ' + this.name);
}
};
// 创建一个新对象,它的原型是base
var obj = Object.create(base);
// 在新对象中添加一个属性
obj.age = 18;
// 调用对象的方法,会沿着原型链找到基础对象的方法
obj.sayHello(); // 输出:Hello, base
console.log(obj.age); // 输出:18
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
- eg2
# 1.1 原型链继承2
function Animal(name) {
this.name = name;
this.hobbies = ['running', 'playing'];
}
// 添加一些方法到Animal的原型对象中
Animal.prototype.eat = function () {
console.log(this.name + ' is eating.');
};
function Cat(name) {
this.name = name;
}
Cat.prototype = new Animal(); //子类型的原型为父类型的一个实例对象
//原型对象指向自己本身
Cat.prototype.constructor = Cat;
// 添加一些方法到Cat对象的原型对象中
Cat.prototype.meow = function () {
console.log(this.name + ' is meowing.');
};
var cat1 = new Cat('短尾'); //
var cat2 = new Cat('折耳');
console.log(cat1.name); //短尾
console.log(cat2.name); //折耳
console.log(cat1.eat()); //短尾 is eating.
console.log(cat2.eat()); //折耳 is eating.
console.log(cat1.meow()); //短尾 is meowing.
console.log(cat1 instanceof Cat); //true
console.log(cat1 instanceof Animal); //true
cat1.hobbies.push('eating'); // 更改一个子类的引用属性,其他子类也会受影响
console.log(cat2.hobbies); //['running','playing','eating']
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
30
31
32
33
34
35
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
30
31
32
33
34
35
总结优缺点
- 优点
原型继承的优点是可以节省内存,因为新对象只需要引用原型对象,而不需要复制它。
- 缺点
- 缺点是如果原型对象中的属性被修改,那么所有继承它的对象都会受到影响。
- 创建子类实例时,无法向父类构造函数传参
# 2. 构造函数继承
概念: 通过在子类构造函数中调用父类构造函数的方式,让子类对象可以继承父类对象上的属性和方法;
原理:在子类构造函数中调用父类构造函数,可以在子类构造函数中使用
call()
和apply()
方法[改变this指向]
function Animal(name, age) {
this.name = name;
this.age = { age };
this.hobbies = ['running', 'playing'];
}
// 添加一些方法到Animal的原型对象中
Animal.prototype.eat = function () {
console.log(this.name + ' is eating.');
};
function Cat(name, age, color) {
//通过在构造函数中调用
Animal.call(this, name, age);
this.color = color;
}
// 添加一些方法到Cat对象的原型对象中
Cat.prototype.meow = function () {
console.log(this.name + ' is meowing.');
};
var cat1 = new Cat('短尾', 1, 'blue');
var cat2 = new Cat('折耳', 2, 'yellow');
console.log(cat1.name); //短尾
console.log(cat2.name); //折耳
try {
console.log(cat1.eat()); // TypeError: cat1.eat is not a function
console.log(cat2.eat()); // TypeError: cat2.eat is not a function
} catch (e) {
console.log(e);
}
console.log(cat1.meow()); //短尾 is meowing.
console.log(cat1 instanceof Cat); //true
console.log(cat1 instanceof Animal); //false
cat1.hobbies.push('eating'); // 更改一个子类的引用属性,其他子类也会受影响
console.log(cat2.hobbies); //['running','playing']
console.log(cat1.age.age); //1
console.log(cat2.age.age); //2
/***
* 优点:
* 1.可以在子类实例中直接向父类构造函数传参
* 2.父类的引用属性不会被子类共享
缺点:
*1.无法继承父类原型上的属性与方法
*/
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 3. 组合继承
概念: 结合原型继承和构造函数继承,既能继承父类原型上的属性和方法,也能继承父类构造函数中定义的属性和方法
原理: 组合上述两种方法就是组合继承。用原型链实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的继承
function Animal(name) {
this.name = name;
this.hobbies = ['running', 'playing'];
}
// 添加一些方法到Animal的原型对象中
Animal.prototype.eat = function () {
console.log(this.name + ' is eating.');
};
function Cat(name, age) {
Animal.call(this, name);
this.age = age;
}
Cat.prototype = new Animal(); //子类型的原型为父类型的一个实例对象
//原型对象指向自己本身
Cat.prototype.constructor = Cat;
// 添加一些方法到Cat对象的原型对象中
Cat.prototype.meow = function () {
console.log(this.name + ' is meowing.');
};
var cat1 = new Cat('短尾'); //
var cat2 = new Cat('折耳');
console.log(cat1.name); //短尾
console.log(cat2.name); //折耳
console.log(cat1.eat()); //短尾 is eating.
console.log(cat2.eat()); //折耳 is eating.
console.log(cat1.meow()); //短尾 is meowing.
console.log(cat1 instanceof Cat); //true
console.log(cat1 instanceof Animal); //true
cat1.hobbies.push('eating'); // 更改一个子类的引用属性,其他子类也会受影响
console.log(cat1.hobbies); // ['running', 'playing', 'eating']
console.log(cat2.hobbies); // ['running', 'playing']
/**
* 优点:
* 1.可以在子类实例中直接向父类构造函数传参
* 2. 通过子类实例可以直接访问父类原型链和实例的成员
* 缺点:
* 1. 调用了两次supertype构造函数,一次在赋值Cat的原型时,一次在实例化子类时call调用,这次调用会屏蔽原型中的两个同名属性。
*/
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
TIP
最后欢迎大家留言交流