Javascript 如何实现继承?

这篇具有很好参考价值的文章主要介绍了Javascript 如何实现继承?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简单来说

  • js 实现继承的方式有很多种,比如 原型链继承、借用构造函数继承、组合继承、寄生继承、寄生组合继承、ES6 新增的 extends 继承
  • 一般我开发中用的比较多的就是 原型链继承 还有 class 类函数继承。 其他的基本用得少,主要是平时看一些技术博客类文章了解过一些。

继承是什么?

继承(inheritance)是面向对象软件技术当中的一个概念。

如果一个类别 B“继承自”另一个类别 A,就把这个 B 称为“A 的子类”,而把 A 称为“B 的父类别”也可以称“A 是 B 的超类”

继承的优点: 不劳而获, 继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码

在子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能

虽然JavaScript并不是真正的面向对象语言,但它天生的灵活性,使应用场景更加丰富

JavaScript想实现继承的目的:重复利用另外一个对象的属性和方法。

常见的继承方式?

一.原型链继承

原型链继承是比较常见的继承方式之一,其中涉及的构造函数、原型和实例,三者之间存在着一定的关系,即每一个构造函数都有一个原型对象,原型对象又包含一个指向构造函数的指针,而实例则包含一个原型对象的指针,例如:

function Parent() {
  this.name = 'parent1'
  this.play = [1, 2, 3]
}
function Child() {
  this.type = 'child2'
}
Child1.prototype = new Parent()
console.log(new Child())

 上面代码看似没问题,实际存在潜在问题

var s1 = new Child2()
var s2 = new Child2()
s1.play.push(4)
console.log(s1.play, s2.play) // [1,2,3,4]

 改变s1play属性,会发现s2也跟着发生变化了,这是因为两个实例使用的是同一个原型对象,内存空间是共享的

二.构造函数继承(借助 call)

function Parent() {
  this.name = 'parent1'
}

Parent.prototype.getName = function () {
  return this.name
}

function Child() {
  Parent1.call(this)
  this.type = 'child'
}

let child = new Child()
console.log(child) // 没问题
console.log(child.getName()) // 会报错

可以看到,父类原型对象中一旦存在父类之前自己定义的方法,那么子类将无法继承这些方法

相比第一种原型链继承方式,父类的引用属性不会被共享,优化了第一种继承方式的弊端,但是只能继承父类的实例属性和方法,不能继承原型属性或者方法

三.组合继承

前面我们讲到两种继承方式,各有优缺点。组合继承则将前两种方式继承起来

function Parent3() {
  this.name = 'parent3'
  this.play = [1, 2, 3]
}

Parent3.prototype.getName = function () {
  return this.name
}
function Child3() {
  // 第二次调用 Parent3()
  Parent3.call(this)
  this.type = 'child3'
}

// 第一次调用 Parent3()
Child3.prototype = new Parent3()
// 手动挂上构造器,指向自己的构造函数
Child3.prototype.constructor = Child3
var s3 = new Child3()
var s4 = new Child3()
s3.play.push(4)
console.log(s3.play, s4.play) // 不互相影响
console.log(s3.getName()) // 正常输出'parent3'
console.log(s4.getName()) // 正常输出'parent3'

将 原型链 和 借用构造函数 的组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性,这种方式看起来就没什么问题,方式一和方式二的问题都解决了,但是从上面代码我们也可以看到Parent3 执行了两次,造成了多构造一次的性能开销

四.原型式继承

主要借助Object.create方法实现普通对象的继承

let parent4 = {
  name: 'parent4',
  friends: ['p1', 'p2', 'p3'],
  getName: function () {
    return this.name
  },
}

let person4 = Object.create(parent4)
person4.name = 'tom'
person4.friends.push('jerry')

let person5 = Object.create(parent4)
person5.friends.push('lucy')

console.log(person4.name) // tom
console.log(person4.name === person4.getName()) // true
console.log(person5.name) // parent4
console.log(person4.friends) // ["p1", "p2", "p3","jerry","lucy"]
console.log(person5.friends) // ["p1", "p2", "p3","jerry","lucy"]

 这种继承方式的缺点也很明显,因为Object.create方法实现的是浅拷贝,多个实例的引用类型属性指向相同的内存,存在篡改的可能

五.寄生式继承

寄生式继承在上面继承基础上进行优化,利用这个浅拷贝的能力再进行增强,添加一些方法

let parent5 = {
  name: 'parent5',
  friends: ['p1', 'p2', 'p3'],
  getName: function () {
    return this.name
  },
}

function clone(original) {
  let clone = Object.create(original)
  clone.getFriends = function () {
    return this.friends
  }
  return clone
}

let person5 = clone(parent5)

console.log(person5.getName()) // parent5
console.log(person5.getFriends()) // ["p1", "p2", "p3"]

 创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象。

六.寄生组合式继承

寄生组合式继承,借助解决普通对象的继承问题的Object.create 方法,在前面几种继承方式的优缺点基础上进行改造,这也是所有继承方式里面相对最优的继承方式

function clone(parent, child) {
  // 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程
  child.prototype = Object.create(parent.prototype)
  child.prototype.constructor = child
}

function Parent6() {
  this.name = 'parent6'
  this.play = [1, 2, 3]
}
Parent6.prototype.getName = function () {
  return this.name
}
function Child6() {
  Parent6.call(this)
  this.friends = 'child5'
}

clone(Parent6, Child6)

Child6.prototype.getFriends = function () {
  return this.friends
}

let person6 = new Child6()
console.log(person6) //{friends:"child5",name:"child5",play:[1,2,3],__proto__:Parent6}
console.log(person6.getName()) // parent6
console.log(person6.getFriends()) // child5

可以看到 person6 打印出来的结果,属性都得到了继承,方法也没问题

@使用ES6 中的extends关键字直接实现 JavaScript的继承

class Person {
  constructor(name) {
    this.name = name
  }
  // 原型方法
  // 即 Person.prototype.getName = function() { }
  // 下面可以简写为 getName() {...}
  getName = function () {
    console.log('Person:', this.name)
  }
}
class Gamer extends Person {
  constructor(name, age) {
    // 子类中存在构造函数,则需要在使用“this”之前首先调用 super()。
    super(name)
    this.age = age
  }
}
const asuna = new Gamer('Asuna', 20)
asuna.getName() // 成功访问到父类的方法

利用babel工具进行转换,我们会发现extends实际采用的也是寄生组合继承方式,因此也证明了这种方式是较优的解决继承的方式

总结:

Javascript 如何实现继承?,javascript,开发语言

 通过Object.create 来划分不同的继承方式,最后的寄生式组合继承方式是通过组合继承改造之后的最优继承方式,而 extends 的语法糖和寄生组合继承的方式基本类似文章来源地址https://www.toymoban.com/news/detail-567967.html

到了这里,关于Javascript 如何实现继承?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第3集丨JavaScript 使用原型(prototype)实现继承——最佳实战1

    在 JavaScript 中, 继承机制的基础是 原型 ,(包括内部原型 __proto__ 和 prototype )。当访问一个对象的属性时, JavaScript 引擎是这么搜索的:如果在本对象中找不到一个属性时,就会去其原型对象中找,如果原型对象中还没找到的话,就去到原型对象中的原型中去找,直到顶级

    2024年02月15日
    浏览(71)
  • 第6集丨JavaScript 使用原型(prototype)实现继承——最佳实战3

    对于继承应用来说,主要目标是将一些现有的功能归为己有。也就是说,我们在新建一个对象时,通常首先应该继承于现有对象,然后在为其添加额外的方法和属性。对此,我们可以通过一个函数调用来完成,并且在其中混合使用我们刚才所讨论的两种方式: 使用原型继承的

    2024年02月16日
    浏览(49)
  • 第4集丨JavaScript 使用原型(prototype)实现继承——最佳实战2

    书接上集,在上集中我们给出了一个需求说明,要求利用现学的知识实现原型( prototype )继承,并且我们给出了三种实现方式。但是这三种方式各自有优缺点,都不能很好的满足要求,那是否还有其他更好的实现方式呢? 在看本文之前,诸位可以自己思考下?带着问题去学

    2024年02月12日
    浏览(47)
  • 【面试题】关于JavaScript实现继承的六大方案,你都了解过吗?

    ​ 前后端面试题库 (面试必备) 推荐:★★★★★ 地址:前端面试题库  web前端面试题库 VS java后端面试题库大全 面试官:“你说说 JavaScript 中实现继承有哪几种方法?” 紧张的萌新:“额,class 中用 extends 实现继承,然后...没了...” 面试官:“...” ······ 想必绝大

    2024年02月02日
    浏览(44)
  • SAP Fiori开发中的JavaScript基础知识15 - 原型,object,constructor,class,继承

    本文将介绍JavaScript中的核心概念 - 原型,并会介绍基于原型的应用场景object,constructor,class,继承。 本文会将这几个核心概念汇总在一篇博客中,因为这些概念是触类旁通的,希望对你有帮助。 在JavaScript中,几乎所有的东西都是对象,每个对象都有一个 特殊的内部属性

    2024年04月23日
    浏览(122)
  • javaScript手写专题——实现instanceof/call/apply/bind/new的过程/继承方式

    目录 原型链相关 手写instanceof 实现一个_instance方法,判断对象obj是否是target的实例  测试  手写new的过程 实现一个myNew方法,接收一个构造函数以及构造函数的参数,返回构造函数创建的实例对象 测试myNew方法 手写类的继承 ES6:class+extends实现继承 组合继承:调用两次父类

    2024年04月14日
    浏览(92)
  • 开发语言漫谈-JavaScript

           JavaScript、Java名字很相近,但它们没有任何亲缘关系,是由不同公司开发的编程语言。Java由Sun公司(后被Oracle收购)开发,JavaScript最初是由Netscape公司开发的(当年浏览器的霸主)。JavaScript最初的名字是 LiveScript,Netscape将其命名为 JavaScript,无非是蹭 Java流量。当

    2024年04月16日
    浏览(50)
  • JavaScript类继承extends

    继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易,不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。 这个已有的类称为 基类(父类) ,新建的类称为 派生类(子类) 。 JavaScript 类继承使用

    2024年02月13日
    浏览(38)
  • 建站系列(五)--- 前端开发语言之HTML、CSS、JavaScript

    建站系列(一)— 网站基本常识 建站系列(二)— 域名、IP地址、URL、端口详解 建站系列(三)— 网络协议 建站系列(四)— Web服务器之Apache、Nginx 建站系列(五)— 前端开发语言之HTML、CSS、JavaScript 建站系列(六)— 后端开发语言 建站系列(七)— 常用前后端框架

    2024年02月09日
    浏览(56)
  • JavaScript:ES6中类与继承

    在JavaScript编程中,ES6引入了一种更现代、更清晰的方式来定义对象和实现继承,那就是通过类和继承机制。本文将以通俗易懂的方式解释ES6中类与继承的概念,帮助你更好地理解和应用这些特性。 1. 类的创建与使用 类是一种模板,用于创建对象。在ES6中,我们可以使用 cl

    2024年02月13日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包