前端继承理解

183 阅读2分钟

继承

核心;实例父对象属性方法继承(复制) 原型链方法属性的继承(修改原型对象 且 constructor指向子对象)

构造器方式

本质上:创建子类实例调用父对象的构造函数 相当于子实例都会将父对象的属性复制一边(没有需改子对象的原型对象

缺点:

只能继承父对象的本身的方法和属性 不继承原型链上属性和方法

相对来说 无法实现复用 影响性能

/* 父对象 */
function parent() {
  this.name = 'chuguo', 
  this.arr = [1, 2, 3]
}
parent.prototype.getName = function () {
  return this.name
}
​
/* 子对象 */
function child() {
  this.test = 'test'
  /* 复制父对象方法和属性 */
  parent.call(this)
}
​
child.prototype.getTest = function () {
  return this.test
}
​
const child1 = new child()
const child2 = new child()
console.log(child1.arr, child2.arr)//[ 1, 2, 3 ] [ 1, 2, 3 ]
child1.arr.push(4)
console.log(child1.arr, child2.arr)//[ 1, 2, 3, 4 ] [ 1, 2, 3 ]console.log(child1.getTest())// test
console.log(child1.getName())// 报错

原型继承方式

本质上:修改原型对象 代替是一个新类型的实例

缺点:

在原型链上查找新的方法或属性时,对父对象的属性(引用类型)上的修改会影响到所有子对象实例

/* 父对象 */
function parent() {
  this.name = 'chuguo', 
      this.arr = [1, 2, 3]
}
parent.prototype.getName = function () {
  return this.name
}
​
/* 子对象 */
function child() {
  this.test = 'test'
}
/* 修改原型对象为父对象的实例 */
child.prototype = new parent()
​
child.prototype.getTest = function () {
  return this.test
}
​
const child1 = new child()
const child2 = new child()
console.log(child1.arr, child2.arr)//[ 1, 2, 3 ] [ 1, 2, 3 ]
/* 修改父对象的引用类型属性 */
child1.arr.push(4)
console.log(child1.arr, child2.arr)//[ 1, 2, 3, 4 ] [ 1, 2, 3, 4 ]

组合继承方式

本质上:对于原型链的方法和属性 采用原型链继承 对于实例属性采用构造器继承

缺点:

原型上存在两根相同的属性方法

对于祖对象的引用类型上会影响所有子实例的访问(尽量实现单继承 类似于Java)

/* 父对象 */
function parent() {
  ;(this.name = 'chuguo'), (this.arr = [1, 2, 3])
}
parent.prototype.getName = function () {
  return this.name
}
parent.prototype.ans = [4, 3, 2]
​
/* 子对象 */
function child() {
  /* 复制父对象方法和属性 最好设置在第一行 便于子对象重写相应的方法属性*/
  parent.call(this)
  this.test = 'test'
  this.name = 'test'
}
​
child.prototype = new parent()
/* 重写构造器 指向child自己的构造器 */
child.prototype.constructor = child
​
child.prototype.getTest = function () {
  return this.test
}
​
const child1 = new child()
const child2 = new child()
​
console.log(child1.arr, child2.arr) //[ 1, 2, 3 ] [ 1, 2, 3 ]
child1.arr.push(4)
console.log(child1.arr, child2.arr) //[ 1, 2, 3, 4 ] [ 1, 2, 3 ]/* 祖对象的方法属性修改与访问 */
console.log(child1.ans, child2.ans) //[ 4, 3, 2 ] [ 4, 3, 2 ]
child1.ans.push(1)
console.log(child1.ans, child2.ans) //[ 4, 3, 2, 1 ] [ 4, 3, 2, 1 ]

寄生式继承方式

核心:在原型对象基础上 增强对象 返回构造函数

缺点:父对象的引用类型的共享修改

寄生组合式继承方式

function inheritPrototype(subType, superType){
  var prototype = Object.create(superType.prototype); // 创建对象,创建父类原型的一个副本
  prototype.constructor = subType;                    // 增强对象,弥补因重写原型而失去的默认的constructor 属性
  subType.prototype = prototype;                      // 指定对象,将新创建的对象赋值给子类的原型
}
​
/*
  代替:
    child.prototype = new parent()
    child.prototype.constructor = child
*/

ES6方式

exrends核心代码

function _inherits(subType, superType) {
    // 创建对象,创建父类原型的一个副本
    // 增强对象,弥补因重写原型而失去的默认的constructor 属性
    // 指定对象,将新创建的对象赋值给子类的原型
    subType.prototype = Object.create(superType && superType.prototype, {
        constructor: {
            value: subType,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    
    if (superType) {
        Object.setPrototypeOf 
            ? Object.setPrototypeOf(subType, superType) 
            : subType.__proto__ = superType;
    }
}

\