写在前面:在JavaScript中,继承有多种方式,本章将对比一些 ES5 中的继承方式和 ES6 中的 extends 关键字。
function Parent() {
this.name = 'Joker'
this.arr1 = ['a', 'b', 'c', 'd']
}
Parent.prototype.arr2 = [1, 2, 3, 4]
Parent.prototype.toString = function () {
return this.name
}
function Child() {
this.name = 'Devin'
}
文中所有举例均以上述代码为基础。
3.1 原型链法(仿传统)
- 代码示例
Child.prototype = new Parent()
Child.prototype.constructor = Child
let c = new Child()
console.log(c.toString()) //Devin
-
所属模式
- 基于构造器工作的模式
- 使用原型链模式
-
技术注解
- 默认继承机制
- 可以将方法与属性集中可重用的部分迁移到原型链中,而将不可重用的部分设置为对象自身的属性
3.2 仅从原型继承法
- 代码示例
Child.prototype = Parent.prototype
Child.prototype.constructor = Child
-
所属模式
- 基于构造器工作的模式
- 原型拷贝模式(不存在原型链,所有对象共享一个原型)
-
技术注解
- 效率上会有较好的表现
- 原型链的查询会比较快,因此这里不存在原型链
- 其缺陷在于,子对象的修改会影响父对象
3.3 临时构造器法
- 代码示例
function extend(child,parent){
let F = function (){}
F.prototype = parent.prototype
child.prototype = new F()
child.prototype.constructor = child
child.uber = parent.prototype
}
-
所属模式
- 基于构造器工作的模式
- 使用原型链模式
-
技术注解
- 此模式与 3.1 不同,它仅继承父对象的原型属性
- 该模式还为访问父对象提供了便利
3.4 原型属性拷贝
- 代码示例
function extend2(child, parent) {
let c = child.prototype
let p = parent.prototype
for (let i in p) {
c[i] = p[i]
}
c.uber = p
}
-
所属模式
- 基于构造器工作的模式
- 拷贝属性模式
- 使用原型模式
-
技术注解
- 将父对象原型中的内容全部转换成子对象原型属性
- 原型链本身也更短
3.5 全属性拷贝法(浅拷贝)
- 代码示例
function extendCopy(p) {
let c = {}
for (let i in p) {
c[i] = p[i]
}
c.uber = p
return c
}
-
所属模式
- 基于对象工作模式
- 属性拷贝模式
-
技术注解
- 非常简单
- 没有使用原型属性
3.6 深拷贝法
- 代码示例
function deepCopy(child, parent) {
let c = child || {}
for (let i in p) {
if (typeof p[i] == 'object') {
c[i] = Array.isArray(p[i]) ? [] : {}
deepCopy(c[i], p[i])
} else {
c[i] = p[i]
}
}
return c
}
- 所属模式
- 基于对象工作模式
- 属性拷贝模式
3.7 原型继承法
- 代码示例
function object(o) {
let F = function () {}
F.prototype = o
return new F()
}
-
所属模式
- 基于对象工作模式
- 使用原型链模式
-
技术注解
- 直接在对象之间构建继承关系
- 发挥原型固有优势
3.8 拓展与增强模式
- 代码示例
function objectPlus(o, stuff) {
let n
let F = function () {}
F.prototype = o
n = new F()
n.uber = o
for (let i in stuff) {
n[i] = stuff[i]
}
return n
}
-
所属模式
- 基于对象工作模式
- 使用原型链模式
- 属性拷贝模式
-
技术注解
- 该方法为原型继承法和属性拷贝法的混合应用
- 通过一个函数一次性完成继承和扩展
3.9 多重继承法
- 代码示例
function multi() {
let n = {}
let stuff
for (let i = 0; i < arguments.length; i++) {
stuff = arguments[i]
for (let k in stuff) {
n[k] = stuff[k]
}
}
return n
}
-
所属模式
- 基于对象工作模式
- 属性拷贝模式
-
技术注解
- 一种混合插入式(mixin-style)继承实现
3.10 构造器借用法
- 代码示例
function child() {
parent.apply(this, arguments)
}
-
所属模式
- 使用构造器工作模式
-
技术注解
- 只继承父对象的自身属性
- 便于子对象继承某对象的具体属性
ES6中类与继承
- 代码示例
// 重写类与继承
class Parent {
constructor() {
this.name = 'Joker'
}
toString() {
return this.name
}
}
Parent.prototype.arr2 = [1, 2, 3, 4]
class Child extends Parent {
constructor() {
super()
this.name = 'Devin'
}
}
let c = new Child()
console.log(c.toString()) //Devin