原型、原型链和继承
# 原型
# 概述
每一个函数都有一个prototype属性,称之为为原型;因为这个属性值是一个对象称之为原型对象
# 作用
- 存放属性和方法 上代码:
// 创建对象实例
const arr = new Array(1,3,5)
// 我们在构造函数上挂载一个方法
Array.prototype.map = function () {
}
// 实例对象又有个__proto__属性指向prototype原型对象
arr.__proto__ = Array.prototype // 等价的
arr.map() // 我们就能使用构造函数上的方法
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
分析:
构造函数Array有个属性prototype指向原型对象,比如我们挂载一个map方法;而构造函数又指向实例对象,恰好实例对象上又有个属性__proto___,
arr.proto = Array.prototype ,构造函数的方法可以在实例对象上使用
# 原型链
# 继承
# 原型链继承
上代码:
function Father() {
this.name = 'll'
this.age = 34
this.obj = {
num: 33
}
this.play = function(){
console.log(this.name)
}
}
Father.prototype.say = function () {
console.log('会唱歌')
}
function Son() {
// Father.call(this) // 构造函数call方法继承
}
Son.prototype = new Father()
const ldh1 = new Son()
ldh1.name = 'lisi'
ldh1.obj.num = 66
console.log(ldh1.name) //lisi
console.log(ldh1.obj) // {num: 66}
ldh1.play() // lisi
ldh1.say() // 会唱歌
console.log('-----------')
const ldh2 = new Son()
console.log(ldh2.name) // ll
console.log(ldh2.obj) // {num: 66}
ldh2.play() // ll
ldh2.say() // 会唱歌
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
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
优点:
共享父类属性和方法
缺点:
1.父类所有的引用类型数据都会被子类共享,更改一个子类的数据其他数据也会跟着一起变化
2.子类实例不能给父类构造函数传参
# 构造函数继承
上代码:
function Father() {
this.name = 'll'
this.age = 34
this.obj = {
num: 33
}
this.play = function(){
console.log(this.name)
}
}
Father.prototype.say = function () {
console.log('会唱歌')
}
function Son() {
Father.call(this) // 构造函数call方法继承
}
// Son.prototype = new Father()
const ldh1 = new Son()
ldh1.name = 'lisi'
ldh1.obj.num = 66
console.log(ldh1.name) //lisi
console.log(ldh1.obj) // {num: 66}
ldh1.play() // lisi
ldh1.say() // ldh1.say is not a function
console.log('-----------')
const ldh2 = new Son()
console.log(ldh2.name) // ll
console.log(ldh2.obj) // {num: 66}
ldh2.play() // ll
ldh2.say() // ldh2.say is not a function
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
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
优点:
父类的引用类型的数据不会被子类共享,不会互相影响
缺点:
子类不能访问父类原型属性上的方法
# 组合继承
上代码:
function Father() {
this.name = 'll'
this.age = 34
this.obj = {
num: 33
}
this.play = function(){
console.log(this.name)
}
}
Father.prototype.say = function () {
console.log('会唱歌')
}
function Son() {
Father.call(this) // 构造函数call方法继承
}
Son.prototype = new Father()
const ldh1 = new Son()
ldh1.name = 'lisi'
ldh1.obj.num = 66
console.log(ldh1.name) //lisi
console.log(ldh1.obj) // {num: 66}
ldh1.play() // lisi
ldh1.say() // 会唱歌
console.log('-----------')
const ldh2 = new Son()
console.log(ldh2.name) // ll
console.log(ldh2.obj) // {num: 66}
ldh2.play() // ll
ldh2.say() // 会唱歌
console.log(ldh2) // 打印下图
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
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
优点:
1.父类可以共用
2.父类引用类型的数据不会共享
缺点:
会调用两次父类构造函数,会有两份一样的属性和方法,影响性能
# 寄生组合继承
上代码:
function Father() {
this.name = 'll'
this.age = 34
this.obj = {
num: 33
}
this.play = function(){
console.log(this.name)
}
}
Father.prototype.say = function () {
console.log('会唱歌')
}
function Son() {
Father.call(this) // 构造函数call方法继承
}
// 中间做了一个中转
const Fn = function() {}
// 把父类的原型直接赋到新的构造函数原型
Fn.prototype = Father.prototype
// 然后让子类原型指向空的实例对象
Son.prototype = new Fn()
// 别忘了这一步
Son.prototype.constructor = Son
const ldh1 = new Son()
ldh1.name = 'lisi'
ldh1.obj.num = 66
console.log(ldh1.name) //lisi
console.log(ldh1.obj) // {num: 66}
ldh1.play() // lisi
ldh1.say() // 会唱歌
console.log('-----------')
const ldh2 = new Son()
console.log(ldh2.name) // ll
console.log(ldh2.obj) // {num: 66}
ldh2.play() // ll
ldh2.say() // 会唱歌
console.log(ldh2)
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
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
说明:ES5最优继承,中间做了一个中转,我们创建一个空的构造函数,把父类的原型直接赋到新的构造函数原型,然后让子类原型指向空的实例对象
# class类继承
上代码:
class Father {
constructor() {
this.name = 'll'
this.age = 34
this.obj = {
num: 33
}
this.play = function(){
console.log(this.name)
}
}
say = function () {
console.log('会唱歌')
}
}
class Son extends Father {}
const ldh1 = new Son()
ldh1.name = 'lisi'
ldh1.obj.num = 66
console.log(ldh1.name) //lisi
console.log(ldh1.obj) // {num: 66}
ldh1.play() // lisi
ldh1.say() // 会唱歌
console.log('-----------')
const ldh2 = new Son()
console.log(ldh2.name) // ll
console.log(ldh2.obj) // {num: 66}
ldh2.play() // ll
ldh2.say() // 会唱歌
console.log(ldh2)
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
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
说明:最优继承
上次更新: 2023/01/29, 11:01:00