Javascript之对象继承

ES5推荐使用寄生组合继承方式

ES6直接使用Classextends即可

原型继承

优点:

  • 由于方法定义在父类的原型上,复用了父类构造函数原型上的方法

缺点:

  • 创建的子类实例不能传参。
  • 子类实例共享了父类构造函数的引用属性(如:arr
var person = { stu:["x", "y", "z"] } var p1 = Object.create(person) p1.stu.push("A") console.log(person.stu)

借助构造函数实现继承

通过改变 Father 构造函数运行时 this 指向,指向 Son,但是 Father 原型链上的东西没有继承
因此,通过构造函数来实现的继承,只能继承父类构造函数的属性,如果原型 prototype上面还有方法甚至原型链上的方法,不会继承

function Father(name){ this.name = name; this.type = ["x","y","z"] } Father.prototype.sayName = function(){ console.log(this.name) } function Son(name, age) { Father.call(this, name); this.age = age; } const son1 = new Son('wmm', 18) console.log(son1); console.log(son1.name, son1.age, son1.sayName) // wmm 18 undefined

借助原型链实现继承

当我们修改某一个对象时,该函数所产出的所有新实例都会发生改变,这就造成了 数据污染 问题,肯定不是我们想要的。
(因为它们引用的是同一个父类实例对象)

function Father(name) { this.name = name || 'wmm' this.type = ["x","y","z"] } function Son(age) { this.age = age } Son.prototype = new Father() let son1 = new Son(18) let son2 = new Son(20) son1.type.push(100) console.log(son1.type, son2.type) // ["x", "y", "z", 100] ["x", "y", "z", 100]

组合继承

优点:

  • 可传参: 子类实例创建可以传递参数。
  • 方法复用: 同时所有子类可以复用父类的方法。
  • 不共享父类引用属性: 子类的改变不会引起父类引用类型的共享

缺点:

  • 组合继承调用了两次父类的构造函数,造成了不必要的消耗
function Father(name) { this.name = name this.type = ["x","y","z"] } Father.prototype.sayName = function() { console.log(this.name) } function Son(name, age){ Father.call(this, name) this.age = age } Son.prototype = new Father() // Son.prototype.constructor指向Father // 因此我们需要手动纠正,将Son.prototype对象的constructor值改为Son Son.prototype.constructor = Son //优点一:可传参 var son1 = new Son("wmm", 18) var son2 = new Son("wmm66", 20) //优点二:共享父类方法 son1.sayName() // wmm son2.sayName() // wmm66 //优点三:不共享父类引用类型 son1.type.push("Q") console.log(son1.type) // [ 'x', 'y', 'z', 'Q' ] console.log(son2.type) // [ 'x', 'y', 'z' ]

寄生组合继承

ES5继承的最佳方式
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的形式来继承方法。
只调用了一次父类构造函数,效率更高。避免在子类.prototype上面创建不必要的、多余的属性,与其同时,原型链还能保持不变。

核心思想: 组合继承 + 原型继承结合两者的优点。

function Father(name){ this.name = name this.type = ["x","y","z"] } Father.prototype.sayName = function(){ console.log(this.name) } function Son(name, age){ Father.call(this, name) this.age = age } Son.prototype = Object.create(Father.prototype) Son.prototype.constructor = Son var son1 = new Son("wmm", 18) var son2 = new Son("wmm66", 20) son1.sayName() // wmm son2.sayName() // wmm66 son1.type.push("Q") console.log(son1.type) // [ 'x', 'y', 'z', 'Q' ] console.log(son2.type) // [ 'x', 'y', 'z' ]

ES6的extend继承

ES6extend 继承其实就是寄生组合式继承的语法糖

核心思想:

  • extends: 内部相当于设置了 Son.prototype = Object.create(Father.prototype);
  • super(): 内部相当于调用了 Father.call(this)

小结:

  • 子类只要继承父类,可以不写 constructor ,一旦写了,则在 constructor 中的第一句话必须是 super
  • 把父类当做普通方法执行,给方法传递参数,让方法中的 this 是子类的实例
function Father(name){ this.name = name this.type = ["x","y","z"] } Father.prototype.sayName = function() { console.log(this.name) } class Son extends Father{ constructor(name, age) { super(name) this.age = age } } var son1 = new Son("wmm", 18) var son2 = new Son("wmm66", 20) son1.sayName() // wmm son2.sayName() // wmm66 son1.type.push("Q") console.log(son1.type) // ["x", "y", "z", "Q"] console.log(son2.type) // ["x", "y", "z"]

创作不易,若本文对你有帮助,欢迎打赏支持作者!

 分享给好友: