js中如何实现继承

js中的继承方式有多种,原型链继承通过子类型原型指向父类型实例实现,优点是实现简单且方法可复用,缺点是所有实例共享引用类型属性且无法向父类构造函数传参;构造函数继承通过在子类构造函数中调用父类构造函数解决属性共享问题,优点是可传递参数且属性独立,缺点是无法继承父类原型方法且方法不可复用;组合继承结合前两者优点,通过原型链继承原型方法、构造函数继承实例属性,实现了方法复用和属性独立,但父类构造函数被调用两次导致性能浪费;原型式继承基于现有对象创建新对象,适用于无需自定义类型的场景,但存在引用属性共享问题;寄生式继承在原型式继承基础上增强对象,适合临时扩展对象功能,但每次都会创建新方法;寄生组合式继承通过继承父类原型的副本来避免构造函数重复调用,解决了组合继承的性能问题,被认为是目前最理想的继承方式。选择继承方式应根据具体需求权衡。

js中如何实现继承

JS中的继承,简单来说,就是让一个对象拥有另一个对象的属性和方法。实现方式有很多,各有优劣,选择哪种取决于具体需求。

js中如何实现继承

解决方案:

实现JS继承的方法主要有以下几种:原型链继承、构造函数继承(也叫经典继承)、组合继承(原型链继承 + 构造函数继承)、原型式继承、寄生式继承、寄生组合式继承。

js中如何实现继承

如何理解原型链继承的优缺点?

原型链继承的核心在于利用原型对象,子类型的原型指向父类型的一个实例。这样,子类型就可以访问父类型原型上的属性和方法。

优点是实现简单,父类方法可以复用。

js中如何实现继承

缺点也很明显:

子类型的所有实例共享父类型原型上的属性,如果父类型原型属性是引用类型,一个实例修改了,其他实例也会受到影响。创建子类型实例时,没法给父类型构造函数传递参数。

function Parent() {  this.name = 'Parent';  this.colors = ['red', 'blue', 'green'];}Parent.prototype.sayName = function() {  console.log(this.name);}function Child() {  this.childName = 'Child';}Child.prototype = new Parent(); // 关键:让Child的原型指向Parent的实例Child.prototype.constructor = Child; // 修正constructor指向let child1 = new Child();child1.colors.push('black');let child2 = new Child();console.log(child2.colors); // ["red", "blue", "green", "black"]  child2也受到了影响

构造函数继承解决了什么问题,又带来了什么新问题?

构造函数继承,也叫经典继承,通过在子类型的构造函数中调用父类型的构造函数来实现。

优点:

解决了原型链继承中子类型实例共享父类型原型属性的问题。创建子类型实例时,可以向父类型构造函数传递参数。

缺点:

父类型的方法定义在构造函数中,每次创建子类型实例都会重新创建一遍,无法复用。父类型原型上的属性和方法,子类型无法访问。

function Parent(name) {  this.name = name;  this.colors = ['red', 'blue', 'green'];  this.sayName = function() { // 每次new Parent都会重新创建    console.log(this.name);  }}function Child(name) {  Parent.call(this, name); // 关键:在子类型构造函数中调用父类型构造函数  this.childName = 'Child';}let child1 = new Child('Child1');child1.colors.push('black');let child2 = new Child('Child2');console.log(child2.colors); // ["red", "blue", "green"] child2没有受到影响

组合继承为什么被认为是比较完善的继承方式?

组合继承结合了原型链继承和构造函数继承的优点,避免了它们的缺点。

思路是:使用原型链继承来实现对父类型原型属性和方法的继承,使用构造函数继承来实现实例属性的继承。

优点:

父类型的方法可以复用。子类型实例拥有各自独立的属性。创建子类型实例时,可以向父类型构造函数传递参数。

缺点:

父类型构造函数会被调用两次:一次是在设置子类型原型的时候,一次是在创建子类型实例的时候。 这导致父类的属性在子类实例和子类原型中都存在,造成一定的性能浪费。

function Parent(name) {  this.name = name;  this.colors = ['red', 'blue', 'green'];}Parent.prototype.sayName = function() {  console.log(this.name);}function Child(name, age) {  Parent.call(this, name); // 构造函数继承  this.age = age;}Child.prototype = new Parent(); // 原型链继承Child.prototype.constructor = Child; // 修正constructor指向let child1 = new Child('Child1', 10);child1.colors.push('black');let child2 = new Child('Child2', 12);console.log(child2.colors); // ["red", "blue", "green"]child1.sayName(); // Child1child2.sayName(); // Child2

原型式继承和寄生式继承有哪些应用场景?

原型式继承,不用创建构造函数,直接基于现有对象创建一个新对象。Object.create() 就是原型式继承的实现。

let person = {  name: 'Person',  friends: ['Shelby', 'Court', 'Van']};let anotherPerson = Object.create(person);anotherPerson.name = 'Greg';anotherPerson.friends.push('Rob');let yetAnotherPerson = Object.create(person);yetAnotherPerson.name = 'Linda';yetAnotherPerson.friends.push('Barbie');console.log(person.friends); // [ 'Shelby', 'Court', 'Van', 'Rob', 'Barbie' ]

原型式继承的缺点和原型链继承类似,修改一个实例的引用类型属性,会影响到其他实例。

寄生式继承,在原型式继承的基础上,增强对象,返回一个新对象。

function createAnother(original) {  let clone = Object.create(original); // 通过调用函数创建一个新对象  clone.sayHi = function() { // 以某种方式增强这个对象    console.log('hi');  }  return clone; // 返回这个对象}let person = {  name: 'Person',  friends: ['Shelby', 'Court', 'Van']};let anotherPerson = createAnother(person);anotherPerson.sayHi(); // "hi"

寄生式继承的缺点是,每个对象都会创建一遍方法。

原型式继承和寄生式继承,主要用于不需要自定义类型,只是想得到一个对象的副本,并对其进行一些修改的场景。

寄生组合式继承如何解决组合继承的性能问题?

寄生组合式继承,被认为是目前最理想的继承方式。它解决了组合继承中父类构造函数被调用两次的问题。

核心思想是:不通过调用父类构造函数来给子类原型赋值,而是通过创建父类原型的副本来实现。

function inheritPrototype(child, parent) {  let prototype = Object.create(parent.prototype); // 创建父类原型的副本  prototype.constructor = child; // 修正constructor指向  child.prototype = prototype; // 将副本赋值给子类原型}function Parent(name) {  this.name = name;  this.colors = ['red', 'blue', 'green'];}Parent.prototype.sayName = function() {  console.log(this.name);}function Child(name, age) {  Parent.call(this, name);  this.age = age;}inheritPrototype(Child, Parent);let child1 = new Child('Child1', 10);child1.colors.push('black');let child2 = new Child('Child2', 12);console.log(child2.colors); // ["red", "blue", "green"]child1.sayName(); // Child1child2.sayName(); // Child2

inheritPrototype 函数起到了关键作用,它避免了调用 Parent 构造函数,只使用了 Parent.prototype 的副本。

选择哪种继承方式,取决于你的具体需求。 如果只是简单的想复用父类原型上的方法,原型链继承可以考虑。 如果需要传递参数,并且不关心方法复用,构造函数继承可以考虑。 如果追求更完善的继承方式,寄生组合式继承是更好的选择。

以上就是js中如何实现继承的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1512984.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 07:27:36
下一篇 2025年12月20日 07:27:46

相关推荐

  • 如何用React Hooks管理复杂的状态逻辑?

    使用 useReducer 和 useContext 可有效管理 React 复杂状态。首先,useReducer 将多操作状态逻辑集中到 reducer 函数中,通过 dispatch(action) 触发更新,避免分散的 setState;其次,结合 useContext 创建全局状态容器,实现…

    2025年12月20日
    000
  • Mongoose关联查询:通过引用文档的名称字段检索数据

    本文详细介绍了在Mongoose中如何通过引用文档的非ID字段(如分类名称)来检索主文档(如产品)。核心方法是分两步进行:首先根据名称查找引用文档的ID,然后使用该ID来查询主文档。文章还探讨了如何设计Schema以支持单类别或多类别引用,并提供了相应的代码示例和注意事项。 理解Mongoose引用…

    2025年12月20日
    000
  • 如何设计一个可扩展的JavaScript状态管理库?

    答案:设计可扩展JavaScript状态库需从基础状态与变更机制出发,通过state、mutations和commit实现数据源唯一与响应式更新;引入actions处理异步逻辑,并构建中间件系统支持日志、调试等功能,形成链式dispatch调用;支持模块化与命名空间,递归注册子模块并实现动态注册与卸…

    2025年12月20日
    000
  • JavaScript中的函数式编程组合子有哪些实用案例?

    函数式编程中的组合子通过纯函数组合提升代码质量。使用 pipe/compose 实现函数链式调用,如 sanitizeInput 对输入处理;柯里化生成可复用函数,如 whereEq 过滤用户角色;Maybe 避免空值判断,安全访问嵌套属性;Promise.all 协调异步并行,retry 增强请求…

    2025年12月20日
    000
  • 如何利用 Service Worker 实现可靠的离线应用和资源缓存?

    Service Worker 是实现 Web 应用离线可用的核心,通过注册并激活代理、缓存关键资源、拦截请求返回缓存内容,并在更新时清理旧缓存,确保离线体验稳定可靠。 要让 Web 应用在离线状态下依然可用,Service Worker 是核心工具。它充当浏览器与网络之间的代理,能拦截请求并返回缓存…

    2025年12月20日
    000
  • 如何利用 JavaScript 的 Service Worker 实现离线可用的 Web 应用?

    Service Worker通过拦截请求和缓存资源实现离线访问,需在HTTPS环境下注册sw.js文件;安装时预缓存核心资源,激活后采用缓存优先策略响应请求,并在版本更新时清理旧缓存,从而提升Web应用的离线可用性。 要让 Web 应用在离线状态下依然可用,Service Worker 是关键。它是…

    2025年12月20日
    000
  • JavaScript多阶段计时器:实现标签切换时计数器重置的技巧

    本文将指导您如何在JavaScript中构建一个多阶段计时器,特别是在每个阶段(如呼吸练习的不同环节)切换时,如何实现局部计数器自动重置为1。通过引入两个独立的计数变量——一个跟踪整体进度,另一个跟踪当前阶段进度——我们能确保计时器显示符合预期,提供清晰的用户体验。 在开发具有多个顺序阶段的计时器应…

    2025年12月20日
    000
  • 如何用Web Locks API管理资源并发访问?

    Web Locks API 是一种浏览器提供的机制,通过互斥锁协调同源下页面与 Worker 对共享资源的访问。它不锁定硬件资源,而是提供逻辑同步,确保关键代码串行执行,避免竞态条件。核心方法为 navigator.locks.request(lockName, options?, callback…

    2025年12月20日
    000
  • 解决Flexbox六边形网格在窄屏溢出问题:响应式单位vw的应用

    针对Flexbox六边形网格在窄屏设备上出现内容溢出的问题,本教程将深入探讨vh单位在宽度定义上的局限性。核心解决方案是改用vw(视口宽度)单位来定义六边形元素的宽度和水平边距,确保网格能根据视口宽度进行自适应缩放,从而有效避免溢出,实现完美的响应式布局。 理解窄屏溢出问题 在构建响应式布局时,尤其…

    2025年12月20日
    000
  • React列表项点击事件处理与数据获取指南

    本教程旨在解决React应用中列表项点击事件的正确处理方式,以及如何在点击时获取并操作被点击项的数据。文章将详细阐述错误的事件绑定方式及其原因,并提供两种推荐的解决方案:使用匿名箭头函数和定义独立的事件处理函数,以确保组件能够响应用户交互并传递所需数据。 引言:React列表中点击事件的处理 在re…

    2025年12月20日
    000
  • React 列表项点击事件无法触发 active 状态切换的调试与解决方案

    本文旨在解决React列表项点击事件无法正确触发active状态切换的问题。通过分析常见错误原因,如混淆:active伪类和active类名,以及状态更新不正确等,提供清晰的解决方案和代码示例,帮助开发者快速定位并修复问题,实现预期的交互效果。文章将重点讲解如何正确使用状态管理和CSS样式,以确保列…

    2025年12月20日
    000
  • 解决React列表中onClick事件无法触发Active状态切换的问题

    本文旨在帮助开发者解决React列表中点击事件无法正确切换元素Active状态的问题。通过分析常见错误原因,例如混淆:active伪类和active类名,并提供清晰的代码示例和CSS样式,帮助读者理解并掌握正确实现Active状态切换的方法,从而提升用户交互体验。 在React中,实现列表项的点击激…

    2025年12月20日
    000
  • 解决React列表点击事件无法触发Active状态切换的问题

    本文旨在解决React列表中点击事件无法正确触发元素Active状态切换的问题。通过分析常见的代码结构和CSS样式,我们将深入探讨如何正确地使用状态管理和CSS类名,以实现点击列表项时动态改变其样式的效果。本文将提供详细的代码示例和注意事项,帮助开发者避免常见的错误,并构建出交互性更强的用户界面。 …

    2025年12月20日
    000
  • 将扁平化JSON数据转换为多级嵌套结构:JavaScript实现指南

    本教程详细介绍了如何将包含层级信息的扁平化JSON数组转换为具有多级嵌套(subNav)结构的JSON对象。通过迭代处理数据并利用一个映射表追踪每个层级的最新节点,我们可以高效地构建出复杂的树形结构,从而实现数据的清晰组织和展示。 1. 理解问题:扁平化数据与目标结构 在前端开发或数据处理中,我们经…

    2025年12月20日
    000
  • 什么是JavaScript的生成器函数在协程调度中的使用,以及它如何模拟多任务并发执行?

    生成器函数通过yield暂停和next()恢复实现协程调度,在单线程中模拟多任务并发。调度器轮流执行多个生成器,结合Promise可简化异步流程,类似async/await机制。需注意避免同步阻塞、合理处理错误,并优化任务粒度与调度策略以提升性能和响应性。 JavaScript的生成器函数提供了一种…

    2025年12月20日
    000
  • JavaScript中的模块联邦(Module Federation)原理是什么?

    模块联邦通过 exposes 和 remotes 配置实现应用间模块共享,运行时动态加载 remoteEntry.js 并注册远程模块,结合 shared 机制避免依赖重复加载,适用于微前端架构下的独立部署与插件化集成。 模块联邦(Module Federation)是 Webpack 5 引入的一…

    2025年12月20日
    000
  • JavaScript中的模块联邦在微前端中如何应用?

    模块联邦通过运行时共享代码实现微前端高效集成。主应用配置remotes加载远程子应用,子应用用exposes暴露模块,shared确保依赖去重。例如主应用可直接导入userApp/UserList组件,实现跨应用调用。优势包括独立部署、技术栈共存、依赖共享,需注意版本统一与接口稳定。 模块联邦(Mo…

    2025年12月20日
    000
  • React Native中利用AppState区分应用首次启动与从后台唤醒

    本教程探讨如何在React Native应用中,利用AppState精确区分应用首次启动(冷启动)与从后台切换到前台(热启动)。通过巧妙地初始化useState的AppState状态,我们可以有效标识应用的初始启动阶段,从而执行特定的逻辑,优化用户体验。 AppState模块概述 AppState是…

    2025年12月20日
    000
  • 如何构建一个无框架、基于原生Web Components的复杂应用?

    完全可行,通过原生Custom Elements构建组件,结合发布-订阅模式实现状态管理,利用history API实现路由,并通过事件总线完成通信,可构建结构清晰、可维护的大型应用。 构建一个无框架、基于原生 Web Components 的复杂应用是完全可行的,关键在于组织方式、状态管理、路由和…

    2025年12月20日
    000
  • 如何实现一个支持多级撤销的绘图应用?

    使用命令模式封装绘图操作,通过undoStack和redoStack实现多级撤销重做,结合合并操作、快照与差分存储优化性能,确保命令可逆且状态还原准确。 实现一个支持多级撤销的绘图应用,关键在于对用户操作进行有序记录,并能按顺序回退和重做。核心思路是使用命令模式结合历史栈来管理绘图动作。 1. 使用…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信