# JS中继承的概念
通过某种方式让一个对象访问到另一个对象中的属性和方法,我们把这种方法称之为继承
并不是所谓的xxx extends yyy
# 使用继承的意义
有些对象会有方法(动作、行为),而这些方法都是函数,如果把这些方法和函数都放在构造函数中声明就会导致内存的浪费
function Poet () {
this.say=function(){
console.log("你好")
}
}
var p1 = new Poet();
var p2 = new Poet();
// false
console.log(p1.say === p2.say);
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 继承的实现方式
# 原型链继承
Poet.prototype.say = function() {
console.log('你好')
}
1
2
3
2
3
缺点:添加一两个方法无所谓,但是如果方法很多会导致过多得代码冗余
# 原型链继承的改良版
Poet.prototype = {
constructor: Poet,
say: function() {
console.log('你好')
},
write: function() {
console.log('我写了一首诗')
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
注意点
1、一般情况下,应该先改变原型,再创建对象
2、一般情况下,对于新原型,会添加一个constructor属性,从而不破坏原有的原型对象的结构
# 拷贝继承(混入继承:mixin)
# 使用场景
有时候想使用某个对象中的属性,但是又不能直接修改它,于是就可以创建一个该对象的拷贝
var p1 = { age: 2 }
var p2 = p1
p2.age = 18
// 1、修改了o2对象的age属性
// 2、由于o2对象跟o1对象是同一个对象
// 3、所以此时o1对象的age属性也被修改了
// 优化代码
var p3 = { age: 2 }
p3.age = 18
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 拷贝继承的实现
对要拷贝的对象使用for...in循环来创建对象的拷贝,然后就可以对克隆的对象进行属性的修改
function extend (target, source) {
for (let key in source) {
target[key] = source[key]
}
return target
}
extend(target,source)
1
2
3
4
5
6
7
2
3
4
5
6
7
由于拷贝继承在实际开发中使用场景非常多,所以很多库都对此有了实现,例如Jquery中的$.extend
ES6中的 对象扩展运算符: ...
仿佛就是专门为了拷贝继承而生
let source={ name: "李白", age: 15 }
//让target是一个新对象,同时拥有了name、age属性
let target={ ...source }
// 还可以修改source中的属性
let target2={ ...source,age:18 }
1
2
3
4
5
2
3
4
5
# 浅拷贝和深拷贝
- 浅拷贝只是拷贝一层属性,没有内部对象
- 深拷贝其实是利用了递归的原理,将对象的若干层属性拷贝出来
# 原型式继承
Object.create(对象)
- 创建一个纯洁的对象(什么属性都没有)
Object.create(null)
- 创建一个继承自某个父对象的子对象
let parent = { age: 18, gender: 'male' } let student = Object.create(parent)
1
2
3
4
5
# 借用构造函数实现继承
- 使用场景:适用于2种构造函数之间逻辑有相似的情况
function Animal(name, age, gender) { this.name = name this.age = age this.gender = gender } function Person(name, age, gender, say) { this.name = name this.age = age this.gender = gender this.say = function () {} }
1
2
3
4
5
6
7
8
9
10
11 - 原理:函数的call、apply调用方式
function Animal (name,age){ this.name=name; this.age=age; } function Person(name,age,address){ Animal.call(this,name); this.address=address; }
1
2
3
4
5
6
7
8 - 局限性:Animal(父类构造函数)的代码必须完全适用于Person(子类构造函数)