JavaScript的继承

12/29/2022 JavaScriptes6

# 原型链继承

function Parent() {
  this.name = 'april'
}

Parent.prototype.getName = function() {
  console.log(this.name)
}

function Child() {}

Child.prototype = new Parent()

let child = new Child()

console.log(child.getName())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 存在的问题

  • 引用类型的属性被所有实例共享
function Parent() {
  this.names = ['april', 'bran']
  this.age = 24
}

function Child() {}

Child.prototype = new Parent()

let child1 = new Child()

child1.names.push('tony')
child1.age = 26

let child2 = new Child()

console.log(child1.names, child1.age) // ['april', 'bran', 'tony']
console.log(child2.names, child2.age) // ['april', 'bran', 'tony']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 在创建 Child 的实例时,不能向 Parent()传参
function Parent(name) {
  this.name = name
}

function Child() {}

Child.prototype = new Parent()

let parentObj = new Parent('test1')
let childObj = new Child('test2')

console.log(parentObj)
console.log(childObj) // childObj的name属性是undefined
1
2
3
4
5
6
7
8
9
10
11
12
13

# 构造函数继承

function Parent() {
  this.names = ['april', 'bran']
}

function Child() {
  Parent.call(this)
}

let child1 = new Child()

child1.names.push('tony')

let child2 = new Child()

console.log(child1.names) // ['april', 'bran', 'tony']
console.log(child2.names) // ['april', 'bran']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 优点

  • 避免了引用类型的属性被所有实例共享
  • 可以在 Child 中向 Parent 传参
function Parent(name) {
  this.name = name
}

function Child(name) {
  Parent.call(this, name)
}

let child1 = new Child('april')
let child2 = new Child('bran')

console.log(child1.name) // april
console.log(child2.name) // bran
1
2
3
4
5
6
7
8
9
10
11
12
13

# 缺点

  • 方法都在构造函数中定义,每次创建实例都会创建一遍方法

# 组合继承

原型链继承和构造函数继承相结合,融合两者的优点,是常用的继承方式。

function Parent(name) {
  this.name = name
  this.colors = ['red', 'blue', 'green']
}

Parent.prototype.getName = function() {
  console.log(this.name)
}

function Child(name, age) {
  Parent.call(this, name)
  this.age = age
}

Child.prototype = new Parent()
Child.prototype.constructor = Child

let child1 = new Child('april', 24)

child1.colors.push('white')
console.log(child1.name) // april
console.log(child1.age) // 24
console.log(child1.colors) // ['red', 'blue', 'green', 'white']
child1.getName() // april
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 缺点

  • 会调用两次父构造函数

# 优化后的组合继承

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
}

let F = function() {}

F.prototype = Parent.prototype
Child.prototype = new F()

let child1 = new Child('april', 24)

console.log(child1.name) // april
console.log(child1.age) // 24

child1.getName() // april
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 寄生式继承

function createObj(o) {
  let clone = Object.create(o)
  clone.sayHi = function() {
    console.log('hello')
  }
  return clone
}

let temp_obj = {
  name: 'april',
  age: 24,
}

let test = createObj(temp_obj)

console.log(test.name) // april
console.log(test.age) // 24
test.sayHi() // hello
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18