prototype
每个构造函数都有一个prototype
属性,这个属性就是这个构造函数的原型对象。构造函数实例所共享的属性和方法都存在这个原型对象上。
继承
- 原型链继承
基本原理就是让构造函数A的原型对象等于另一个构造函数B的实例,那么A便继承了B
原型链继承有两个问题function Parent() { this.role = 'parent' } function Children() { this.role = 'children' } Children.prototype = new Parent()
- 原型中包含引用类型值的问题
function Parent() { this.colors = ['red', 'blue'] } function Children() {} Children.prototype = new Parent() const children = new Children() const childrenCopy = new Children() children.colors.push('black') console.log(childrenCopy.colors) // ['red', 'blue', 'black'] ```
- 创建子类型实例的时候不能向父构造函数传递参数
- 原型中包含引用类型值的问题
- 借用构造函数 | 伪造对象 | 经典继承
在子类型内部调用父类型函数。就是将所有共享的属性和方法都定义在父类型中,通过call()
和apply()
方法在子类型中执行父类型函数,其本质是将父类型中定义的方法和属性复制一份到子类型中
借用构造函数虽然解决了原型链继承的传参问题和引用类型值的问题,但是它也造成了其它两个问题function Parent(name, sex) { this.name = name this.sex = sex this.getSex = function() { console.log(this.sex) } } function Children(name,sex) { Parent.call(this, name, sex) } const children = new Children('小吴', '男')
- 当父类型中定义方法过多时,会占用很大内存,这样方法复用就无从谈起了,而且父类型的原型对子类型是不可见的
- 当要修改父类型中的一个属性或者方法时,那么修改之前的所有实例都不能及时作出更新
- 组合继承 | 伪经典继承
使用原型链来实现对父类型原型属性和方法的继承,使用借用构造函数实现父类型属性的继承
组合继承避免了原型链继承和借用构造函数继承的缺点,融合了它们的优点,成为了js中最常用的继承模式。但是组合继承也存在一个缺点function Parent(name) { this.name = name } Parent.prototype.getName = function() { console.log(this.name) } function Children(name) { Parent.call(this, name) } Children.prototype = new Parent() const children = new Children('小吴')
- 会调用两次父类型构造函数,造成性能上的浪费
- 原型式继承
原型式继承的inherit
方法本质上是对参数对象的一个浅复制
其问题也和原型链继承相同,都是引用类型值的问题以及向父类型传参的问题function inherit(Parent) { const Fn = function() {} Fn.prototype = Parent return new Fn() } const Parent = { name: '老吴', getName() { console.log(this.name) } } const children = inherit(Parent)
- 寄生式继承
这种继承并没有什么优点,只是提供一种思路而已function inherit(Parent) { const Fn = function() {} Fn.prototype = Parent return new Fn() } function createChildren(Parent) { const children = inherit(Parent) children.sayHi = funtion() { console.log('Hi') } } const Parent = { name: '老吴', getName() { console.log(this.name) } } const children = creatChildren(Parent)
- 寄生组合式继承
这是一种最完美的继承方式
寄生组合式继承主要是为了解决组合式继承中两次调用父类型构造函数的问题的。从代码上来看,使用了function getCopyObj(obj) { const Fn = function() {} Fn.prototype = obj return new Fn() } function inherit(Children, Parent) { const parentPrototype = getCopyObj(Parent.prototype) parentPrototype.constructor = Children Children.prototype = parentPrototype } function Parent(name) { this.name = name } Parent.prototype.getName() { console.log(this.name) } function Children(name) { Parent.call(this, name) } inherit(Children, Parent) const children = new Children('小吴')
getCopyObj
方法和inherit
方法来代替组合式继承中子类型构造函数等于父类型构造函数实例(Children.prototype = new Parent()
),起原理是拷贝父类型构造函数的原型对象,并且修改其constructor
指针位置,然后再赋值给子类型构造函数的原型对象