返回介绍

继承的实现

发布于 2024-09-07 20:34:43 字数 4528 浏览 0 评论 0 收藏 0

原型链继承

原型链继承实现的原理就是将构造函数的原型设置为另一个构造函数的实例对象,这样就可以继承另一个原型对象的所有属性和方法,可以继续往上,最终形成原型链。

function Parent1(name, age) {
  this.name = name,
  this.age = age
}
Parent1.prototype.say = function() {
  console.log(this.name)
}
function Child1(name) {
  this.name = name
}
Child1.prototype = new Parent1()
Child1.prototype.constructor = Child1
let child1 = new Child1('南玖',18)
console.log(child1) //Child1 {name: '南玖'}
child1.say() // 南玖

缺点:

  • 当实现继承后,另一个原型的实例属性,变成了现在这个原型的原型属性,然后该原型的引用类型属性会被所有的实例共享,这样继承原型引用类型属性的实例之间不再具有自己的独特性了。
  • 在创建子类型的实例时,没有办法在不影响所有对象实例的情况下给超类型的构造函数中传递参数。

构造函数继承

为了解决原型中包含引用类型值的问题,开始使用借用构造函数,也叫伪造对象或经典继承

构造函数继承实现的原理就是在子类中调用父类构造函数来实现继承

function Parent2(age) {
  this.age = age
  this.say = function() {
    console.log(this.name)
  }
}
function Child2(name,age,gender) {
  this.name = name
  Parent2.call(this, age)
  this.gender = gender
}
let child2 = new Child2('南玖', 18, 'boy')
console.log(child2) //Child2 {name: '南玖', age: 18, gender: 'boy'}
child2.say() // 南玖

优点: 可以传递参数以及避免了引用类型的属性被所有实例共享

缺点: 所有方法都在构造函数内,每次创建对象都会创建对应的方法,大大浪费内存

组合继承*

也叫伪经典继承,将原型链和借用构造函数的技术组合到一块。使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。

function Parent3(age) {
  this.age = age
}
Parent3.prototype.say = function() {
  console.log(this.name)
}
function Child3(name,age,gender) {
  this.name = name
  Parent3.call(this, age)
  this.gender = gender
}

Child3.prototype = new Parent3
Child3.prototype.constructor = Child3
let child3 = new Child3('南玖', 18, 'boy')
console.log(child3) //Child3 {name: '南玖', age: 18, gender: 'boy'}
child2.say() // 南玖
  • 将 Child3 的原型指定为 Parent3 的一个实例,大致步骤和原型链继承类似,只是多了在 Child3 中借调 Parent3 的过程。
  • 实例属性定义在构造函数中,而方法则定义在构造函数的新原型中,同时将新原型的 constructor 指向构造函数。
  • 可以通过 instanceofisPrototypeOf() 来识别基于组合继承创建的对象。
  • 避免了原型链和借用构造函数的缺陷,融合了它们的优点,成为 JS 中最常用的继承模式。

原型式继承

借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。

function object(obj) {
  function F(){}
  F.prototype = obj
  return new F()
}
let parent4 = {
  age: 18,
  name: '南玖',
  say() {
    console.log(this.name)
  }
}
let child4 = object(parent4)
console.log(child4) 
/**{[[Prototype]]: Object
  age: 18
  name: "南玖"
  say: ƒ say()
  [[Prototype]]: Object
  }
*/
child4.say() // 南玖

在 object() 函数内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例。从本质上讲,object() 对传入其中的对象执行了一次浅复制

  • 这种原型式继承,要求必须要有一个对象可以作为另一个对象的基础
  • 用这种方式创建的对象相当于是传入参数对象的副本

它其实就是 ES5 Object.create 的模拟实现,将传入的对象作为创建对象的原型

在只想让一个对象与另一个对象保持类似的情况下,原型继承是完全可以胜任的。原型模式下的缺点:引用类型属性的共享问题。

寄生继承

寄生式继承与原型式继承紧密相关,与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再返回对象。

function createAnother(original) {
  var clone = object(original) //通过调用函数创建一个新对象
  clone.say = function(){    // 以某种方式来增强这个对象
  console.log('nanjiu')
  };
  return clone      // 返回这个对象
}

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

寄生组合式继承*

组合继承是 JavaScript 最常用的继承模式;不过,它也有自己的不足。组合继承最大的问题就是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。没错,子类型最终会包含超类型对象的全部实例属性,但我们不得不在调用子类型构造函数时重写这些属性。

function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

function prototype(child, parent) {
  var prototype = object(parent.prototype);
  prototype.constructor = child;
  child.prototype = prototype;
}


function Parent6(age) {
  this.age = age
}
Parent6.prototype.say = function() {
  console.log(this.name)
}
function Child6(name, gender) {
  this.name = name
  this.gender = gender
}

// 使用
prototype(Child6, Parent6);
let child6 = new Child6('nanjiu', 'boy')

console.log(child6) // Child6 {name: 'nanjiu', gender: 'boy'}
child6.say() // nanjiu

总结

JavaScript 主要通过原型链实现继承。原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的。这样,子类型就能够访问超类型的所有属性和方法,这一点与基于类的继承很相似。

  • 原型链的问题是对象实例共享所有继承的属性和方法,因此不适宜单独使用。
  • 解决这个问题的技术是借用构造函数,即在子类型构造函数的内部调用超类型构造函数。这样就可以做到每个实例都具有自己的属性,同时还能往超类型构造函数中传递参数,但是没有函数复用。
  • 使用最多的继承模式是组合继承,这种模式使用原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。
  • 此外,还存在下列可供选择的继承模式。
  • 原型式继承,可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅复制。而复制得到的副本还可以得到进一步改造。
  • 寄生式继承,与原型式继承非常相似,也是基于某个对象或某些信息创建一个对象,然后增强对象,最后返回对象。为了解决组合继承模式由于多次调用超类型构造函数而导致的低效率问题,可以将这个模式与组合继承一起使用。
  • 寄生组合式继承,集寄生式继承和组合继承的优点与一身,是实现基于类型继承的最有效方式。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文