xiaochengzi6 / Blog

个人博客
GNU Lesser General Public License v2.1
0 stars 0 forks source link

JS继承的方式以及优缺点 #60

Open xiaochengzi6 opened 1 year ago

xiaochengzi6 commented 1 year ago

主要参考这篇文章js继承的多种方式及优缺点

前置条件,js 继承中对象是由构造函数通过 new 调用创建的,那么继承就需要两个构造函数后者去继承前者,分别称之为子类和父类

原型链继承

缺点:

  1. 继承后的属性要是引用类型修改子类父类中的属性也会改变
  2. 创建子类时不能向父类传递参数

借用构造函数

优点:

  1. 继承的属性是引用类型修改子类并不会影响到父类
  2. 可以向父类传递参数

缺点:

  1. 方法都要在构造函数上定义每一次 new (创建对象) 都要重新创建一遍方法

组合继承

优点:

  1. 通过组合继承可以避免上述缺点并且具有上述的优点

组合继承最大的缺点是会调用两次父构造函数。

原型式继承

function createObj(obj){
  function f(){}
  f.prototype = new obj()
  return new f()
}

缺点:

  1. 包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样

寄生式继承

function createObj(obj){
  var obj = Object.create(obj)
  obj.sayName = function () {}
  return obj
}

缺点:跟借用构造函数模式一样,每次创建对象都会创建一遍方法。

寄生组合式继承

var parent = new function A () {}
var child = new function B () {}

child.prototype = Object.create(patent.prototype)

重点在于:(参考组合继承代码)如果我们不使用 Child.prototype = new Parent() ,而是间接的让 Child.prototype 访问到 Parent.prototype 也就是这样的效果

var parent = new function A () {}
var child = new function B () {}

function c () {}
c.prototytpe = patent.prototype
child.prototype = new c

也就是说在中间做了一次转发从而去继承 parent 原型 抛弃它定义在自身的属性

总结:这种方式的高效率体现它只调用了一次 Parent 构造函数,并且因此避免了在 Parent.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变

xiaochengzi6 commented 1 year ago

ES5 中的继承

ES5 中继承机制是先创建一个独立的子类的实例对像,然后再将父类的方法添加到这个对象上面 实例在前,继承在后的特点 这个性质非常像 new 的调用方式 下面实现一下 new

function myNew (obj){
  var newObj = {}
  newObj.prototype = obj.prototype
  var result = newObj.call(this)
  return result || newObj
}

ES6 中的继承机制

先将父类的属性和方法加载到空对象上,然后再将该对象作为子类的实例 就是“继承在前,实例再后” 最明显的就是使用 class 中继承子类继承与父类必须在 constructor内使用 supper() 才行

class A {}
class B extends A{
  constructor(){
    supper()  
  }
}

调用supper () 会生成一个继承父类的 this 对象所以才能继承父类

es6 实际上是新建了一个 对象 (对象的this 是父类的)也就是说这个对象会拥有父类的所有属性和方法(换句话说是父类的this对象 因为可以通过 this 访问到所有的属性和方法),再通过子类的构造函数中去修改这个 this 对象 从而完成继承

class A {}
class B extends A {
  constructor (...args) {
    supper(...args)
    // 从这里开始就可以操作 this 来修改父类中定义的东西 (个性化子类)
  }
}

特点、差异

es5 中不能去继承原生的构造函数 image 因为无法获取到它(父类)的内部属性从而不能创建和父类一样的子类

function A (){
  Array.call(this)
}
var a = new A()

值得注意的是 这些原生构造函数会忽略 call apply 绑定的 this 原生构造函数的this无法绑定,导致拿不到内部属性

主要就是和 es5 中的继承机制有关,es5 会创建一个对象 再将父类的属性添加到子类上,由于无法获取父类的内部属性从而无法继承

但是 es6 可以 它就是使用 父类的this对象 然后在子类的构造函数中去修改父类的属性或者方法

因为 ES6 是先新建父类的实例对象this,然后再用子类的构造函数修饰this,使得父类的所有行为都可以继承

class A extends B {
constructor(..args){
supper(...args)
} 
}

主要参考文章:阮一峰 es6 入门