06-继承

6/22/2022

# 1. 继承

继承, 可以让多个构造函数之间建立关联, 便于管理和复用

# 1.1 不使用继承

// 分析需求:
// 人类, 属性: name, age   会说话
// 学生, 属性: name, age, className  会说话
// 工人, 属性: name, age, companyName  会说话

// 为什么要有继承:
// 继承: 将多个构造函数, 建立关联, 实现方便管理 和 方便复用

// 角度
// 1. 方法的继承
// 2. 实例化属性过程的复用

function Person (name, age) {
  this.name = name
  this.age = age
}
Person.prototype.sayHi = function() {
  console.log('会说话')
}

function Student (name, age, className) {
  this.name = name
  this.age = age
  this.className = className
}
Student.prototype.sayHi = function() {
  console.log('会说话')
}

function Worker (name, age, companyName) {
  this.name = name
  this.age = age
  this.companyName
}
Worker.prototype.sayHi = function() {
  console.log('会说话')
}
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

# 1.2 继承之原型继承

原型继承: 通过改造原型链, 利用原型链的语法, 实现继承方法!

// 目标: 原型继承 => 继承方法
// 原型继承: 通过改造原型链实现继承, 利用原型链的特征实现继承,所谓的原型继承,就是在改造原型链

// 1. 定义Person构造函数
function Person (name, age) {
  this.name = name
  this.age = age
}
Person.prototype.say = function () {
  console.log('人类会说话')
}

// 2. 定义Student构造函数
function Student (name, age, className) {
  this.name = name
  this.age = age
  this.className = className
}
// 3. 原型继承: 利用原型链, 继承于父级构造函数, 继承原型上的方法
// 语法: 子构造函数.prototype = new 父构造函数()
Student.prototype = new Person()
Student.prototype.constructor = Student;

Student.prototype.study = function() {
  console.log('学生在学习')
}

let stu = new Student('张三', 18, '80期')
stu.say()
console.log(stu)
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

原型链继承的缺点:

  • 如果父中的数据类型是引用数据类型,子对象修改了,另一个子对象也会受影响
  • 创建Child对象是,不能传参

# 1.3 继承之组合继承

// 组合继承: 两种技术的组合, 原型链技术, 借用构造函数(call)结合, 发挥二者之长, 实现继承的方式
// 1. 原型链技术: 改造原型链, 实现继承方法
//    Student.prototype = new Person()
// 2. 实例属性的构造过程没有得到复用, 可以用借用构造函数的方式, 实现复用
//    Person.call(this, name, age)

function Person (name, age) {
  this.name = name 
  this.age = age
}
Person.prototype.sayHi = function() {
  console.log('会说话')
}

function Student (name, age, className) {
  // 不仅要执行Person构造函数, 且要让执行构造函数时的this指向创建出来的实例stu
  // call
  // 1. 调用函数
  // 2. 改变函数执行时的this指向
  Person.call(this, name, age)
  this.className = className
}
Student.prototype = new Person()

const stu = new Student('zs', 7, '一年级一班')
stu.sayHi()
console.log(stu)

// 方法通过 原型继承
// 属性通过 父构造函数的.call(this, name, age)
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

# 1.4 继承之寄生组合继承

function Person (name, age) {
  this.name = name 
  this.age = age
}
Person.prototype.sayHi = function() {
  console.log('会说话')
}

function Student (name, age, className) {
  // 不仅要执行Person构造函数, 且要让执行构造函数时的this指向创建出来的实例stu
  // call
  // 1. 调用函数
  // 2. 改变函数执行时的this指向
  Person.call(this, name, age)
  this.className = className
}
// 构造函数没有必要执行, 我们只需要的是原型链
Student.prototype = Object.create(Person.prototype)

const stu = new Student('zs', 7, '一年级一班')
stu.sayHi()
console.log(stu)


// 总结:
// Object.create() 以参数的对象, 作为新建对象的__proto__属性的值, 返回新建的对象
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

# 1.5 继承之ES6中的继承

// function Person (name, age) {
//   this.name = name
//   this.age = age
// }
// Person.prototype.sayHi = function() {}
// Person.prototype.jump = function() {}


// 人类
class Person {
  // 类似于之前的构造函数
  constructor (name, age) {
    this.name = name
    this.age = age
  }
  // 底层 => 这两个方法, 就是添加到 Person.prototype 上
  sayHi () {
    console.log('你好哇')
  }
  jump () {
    console.log('会跳')
  }
}
const p = new Person('zs', 18)
console.log(p)

// 继承关键字 => extends
// 老师类
class Teacher extends Person {
  // 如果没有提供构造函数, 在继承时, 会默认自动借调父构造函数
  constructor (name, age, lesson) {
    // 你写的构造函数中, 没有借调父构造函数
    super(name, age) // 触发调用父构造函数, 进行实例的属性初始化
    this.lesson = lesson
  }
  teach () {
    console.log('会教书')
  }
}
const teacher = new Teacher('zs', 18, '教体育')
console.log(teacher)
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
Last Updated: 12/25/2022, 10:02:14 PM