面试题: 对象继承的方式有哪些

在 JavaScript 中,对象继承可以通过多种方式实现。每种方法都有其特点和适用场景。以下是几种常见的对象继承方式:

1. 原型链继承(Prototype Chain Inheritance)

这是最基础的对象继承方式,利用了 JavaScript 的原型机制。每个对象都有一个内部属性 [[Prototype]],它指向另一个对象,即该对象的原型。当尝试访问一个对象的属性时,如果对象本身没有这个属性,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或到达原型链的末端(通常是 Object.prototype)。

function Parent() {this.name = 'parent';
}Parent.prototype.sayHello = function() {console.log('Hello from ' + this.name);
};function Child() {}// 设置 Child 的 prototype 为 Parent 的实例
Child.prototype = new Parent();
Child.prototype.constructor = Child; // 修复构造函数指针const child = new Child();
child.sayHello(); // 输出: Hello from parent

缺点:所有子类实例共享同一个父类实例的属性,可能会导致意外的状态共享问题。

2. 构造函数继承(Constructor Function Inheritance)

通过使用 callapply 方法,可以在子类构造函数中调用父类构造函数,从而将父类的属性复制到子类实例上。这种方式可以避免原型链继承中的状态共享问题。

function Parent(name) {this.name = name;
}Parent.prototype.sayHello = function() {console.log('Hello from ' + this.name);
};function Child(name, age) {Parent.call(this, name); // 调用父类构造函数this.age = age;
}const child = new Child('child', 10);
console.log(child.name); // 输出: child
console.log(child.age);  // 输出: 10

缺点:子类不能继承父类的原型方法,需要额外的方法来继承这些方法。

3. 组合继承(Combination Inheritance)

组合继承结合了原型链继承和构造函数继承的优点,既可以通过构造函数继承父类的属性,又可以通过原型链继承父类的方法。

function Parent(name) {this.name = name;this.colors = ['red', 'blue'];
}Parent.prototype.sayHello = function() {console.log('Hello from ' + this.name);
};function Child(name, age) {Parent.call(this, name); // 第一次调用 Parentthis.age = age;
}Child.prototype = new Parent(); // 第二次调用 Parent
Child.prototype.constructor = Child;const child1 = new Child('child1', 10);
const child2 = new Child('child2', 20);child1.colors.push('green');
console.log(child1.colors); // 输出: ['red', 'blue', 'green']
console.log(child2.colors); // 输出: ['red', 'blue']

缺点:两次调用父类构造函数,第一次是在创建子类实例时,第二次是在设置子类原型时,这可能会造成不必要的开销。

4. 原型式继承(Prototypal Inheritance)

这种继承方式不依赖于构造函数,而是直接基于对象创建新的对象。通常使用 Object.create() 方法来实现。

const parent = {name: 'parent',sayHello: function() {console.log('Hello from ' + this.name);}
};const child = Object.create(parent);
child.name = 'child';child.sayHello(); // 输出: Hello from child

优点:简单明了,适合不需要复杂构造函数的情况。

5. 寄生式继承(Parasitic Inheritance)

寄生式继承是原型式继承的增强版,它在创建新对象的基础上,进一步增强对象的功能,然后再返回这个对象。

function createChild(parent) {const child = Object.create(parent); // 使用原型式继承child.sayHi = function() {console.log('Hi from ' + this.name);};return child;
}const parent = {name: 'parent',sayHello: function() {console.log('Hello from ' + this.name);}
};const child = createChild(parent);
child.name = 'child';
child.sayHi(); // 输出: Hi from child

优点:可以自由地添加或修改对象的功能。

6. 寄生组合式继承(Parasitic Combination Inheritance)

寄生组合式继承是组合继承的优化版本,它只调用一次父类构造函数,避免了组合继承中的效率问题。这是目前最常用的继承模式之一。

function inheritPrototype(child, parent) {const prototype = Object.create(parent.prototype); // 创建父类原型的副本prototype.constructor = child; // 修正构造函数指针child.prototype = prototype;   // 将副本赋值给子类的原型
}function Parent(name) {this.name = name;this.colors = ['red', 'blue'];
}Parent.prototype.sayHello = function() {console.log('Hello from ' + this.name);
};function Child(name, age) {Parent.call(this, name); // 只调用一次 Parentthis.age = age;
}inheritPrototype(Child, Parent);const child1 = new Child('child1', 10);
const child2 = new Child('child2', 20);child1.colors.push('green');
console.log(child1.colors); // 输出: ['red', 'blue', 'green']
console.log(child2.colors); // 输出: ['red', 'blue']

优点:只调用一次父类构造函数,避免了重复调用的问题,同时保持了组合继承的优点。

7. 类(Class)继承(ES6+)

ES6 引入了 class 语法糖,使得继承更加简洁和直观。实际上,class 仍然是基于原型的,但它提供了一种更接近传统面向对象语言的语法。

class Parent {constructor(name) {this.name = name;}sayHello() {console.log('Hello from ' + this.name);}
}class Child extends Parent {constructor(name, age) {super(name); // 调用父类构造函数this.age = age;}sayAge() {console.log('I am ' + this.age + ' years old.');}
}const child = new Child('child', 10);
child.sayHello(); // 输出: Hello from child
child.sayAge();   // 输出: I am 10 years old.

优点:语法简洁,易于理解和使用,特别适合面向对象编程。

总结

  • 原型链继承 是最基础的继承方式,但存在状态共享的问题。
  • 构造函数继承 解决了状态共享问题,但无法继承原型方法。
  • 组合继承 结合了两者的优势,但有重复调用父类构造函数的缺点。
  • 原型式继承寄生式继承 更加灵活,适用于不需要复杂构造函数的场景。
  • 寄生组合式继承 是组合继承的优化版本,解决了重复调用的问题,是最推荐的继承方式之一。
  • 类继承 提供了更简洁的语法,适合现代 JavaScript 开发。

选择哪种继承方式取决于具体的需求和项目背景。对于新项目,特别是使用 ES6+ 的项目,推荐使用 class 语法糖来实现继承,因为它不仅语法简洁,而且社区支持广泛。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/66489.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四、VSCODE 使用GIT插件

VSCODE 使用GIT插件 一下载git插件与git Graph插件二、git插件使用三、文件提交到远程仓库四、git Graph插件 一下载git插件与git Graph插件 二、git插件使用 git插件一般VSCode自带了git,就是左边栏目的图标 在下载git软件后vscode的git插件会自动识别当前项目 …

消息队列MQ(二)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 MQ学习笔记 前言一、发送者的可靠性1. 生产者重试机制2. 生产者确认机制3. 实现生产者确认 二、MQ的可靠性1. 数据持久化2. LazyQueue 前言 在用MQ实现异步调用时&#xff0…

数据分析思维(九):分析方法——AARRR模型分析方法

数据分析并非只是简单的数据分析工具三板斧——Excel、SQL、Python,更重要的是数据分析思维。没有数据分析思维和业务知识,就算拿到一堆数据,也不知道如何下手。 推荐书本《数据分析思维——分析方法和业务知识》,本文内容就是提取…

【计算机网络】课程 实验四 配置快速生成树协议(RSTP)

实验四 配置快速生成树协议(RSTP) 一、实验目的 1.理解快速生成树协议RSTP的工作原理。 2.掌握如何在交换机上配置快速生成树。 二、实验分析与设计 【背景描述】 某学校为了开展计算机教学和网络办公,建立了一个计…

Tauri教程-基础篇-第一节 Tauri项目创建及结构说明

“如果结果不如你所愿,就在尘埃落定前奋力一搏。”——《夏目友人帐》 “有些事不是看到了希望才去坚持,而是因为坚持才会看到希望。”——《十宗罪》 “维持现状意味着空耗你的努力和生命。”——纪伯伦 Tauri 技术教程 * 第四章 Tauri的基础教程 第一节…

pyinstaller冻结打包多进程程序的bug:无限创建进程直至系统崩溃

前面写过两篇相关的文章: PyQt应用程序打包Python自动按键 这两篇文章都没有提到下面的这个重要问题: 采用Pyinstaller冻结打包多进程程序时,必须非常小心。这个技术线在Windows上会有一个非常严重的Bug。直接运行打包后的程序会造成无限创…

网络安全-kail linux 网络配置(基础篇)

一、网络配置 1.查看网络IP地址, 我的kail:192.168.15.128 使用ifconfig查看kail网络连接情况,ip地址情况 又复制了一台kail计算机的IP地址。 再看一下windows本机:使用ipconfig进行查看: 再看一下虚拟机上的win7I…

uni app 写的 小游戏,文字拼图?文字拼写?不知道叫啥

从下方的偏旁部首中选在1--3个组成上面文章中的文字&#xff0c;完成的文字标红 不喜勿喷 《满江红》 其中用到了两个文件 strdata.json parameters.json 这两个文件太大 放到资源中了 资源文件 <template><view class"wenzi_page_main"><view c…

分享几个高清无水印国外视频素材网站

在数字内容创作日益盛行的今天&#xff0c;高质量的视频素材成为了视频制作、广告创意和多媒体项目中不可或缺的元素。对于追求专业水准的创作者而言&#xff0c;高清、无水印的视频素材是确保作品质量的基石。以下将分享几个优质的视频素材网站&#xff0c;为您的创作之路提供…

【LLM】大语言模型基础知识及主要类别架构

文章目录 LLM大语言模型1.LLM基础知识1.1大模型介绍:1.2语言模型1.21n-gram语言模型1.22神经网络语言模型1.23基于Transformer的预训练语言模型1.24大语言模型 1.3模型评估指标1.31 BLEU1.32 Rouge指标1.33 困惑度PPL 2.LLM主要类别架构2.1 自编码模型2.2 自回归模型2.3 Encode…

剖析 Claim-Check 模式:以小传大,赋能分布式系统与微服务

1. 前言 1.1 写作背景与目的 在当今分布式系统与微服务架构盛行的时代&#xff0c;服务间的消息传递与数据交换越来越频繁。传统的消息传输在面对海量数据时&#xff0c;往往会遇到以下痛点&#xff1a; 消息体过大&#xff1a;直接通过消息队列或服务间接口发送大体量数据&…

【Uniapp-Vue3】v-if条件渲染及v-show的选择对比

如果我们想让元素根据响应式变量的值进行显示或隐藏可以使用v-if或v-show 一、v-show 另一种控制显示的方法就是使用v-show&#xff0c;使用方法和v-if一样&#xff0c;为true显示&#xff0c;为false则不显示。 二、v-if v-if除了可以像v-show一样单独使用外&#xff0c;还…

JVM实战—OOM的定位和解决

1.如何对系统的OOM异常进行监控和报警 (1)最佳的解决方案 最佳的OOM监控方案就是&#xff1a;建立一套监控平台&#xff0c;比如搭建Zabbix、Open-Falcon之类的监控平台。如果有监控平台&#xff0c;就可以接入系统异常的监控和报警&#xff0c;可以设置当系统出现OOM异常&…

Idea(中文版) 项目结构/基本设置/设计背景

目录 1. Idea 项目结构 1.1 新建项目 1.2 新建项目的模块 1.3 新建项目模块的包 1.4 新建项目模块包的类 2. 基本设置 2.1 设置主题 2.2 设置字体 2.3 设置注释 2.4 自动导包 2.5 忽略大小写 2.6 设置背景图片 3. 项目与模块操作 3.1 修改类名 3.2 关闭项目 1. I…

liunx 中编写 springboot 服务停止时定时检查重启脚本

当服务内存溢出或其他一些原因&#xff0c;导致程序停止运行&#xff0c;服务不可用&#xff0c;为了服务能够及时自动重启&#xff0c;记录一下操作过程&#xff01; 首先编写自动重启的脚本指令&#xff0c;脚本在服务器上编写的&#xff0c;最后不要写好txt文件&#xff0c;…

CV-LLM经典论文解读|VTimeLLM: Empower LLM to Grasp Video MomentsVTimeLLM:赋能大语言模型理解视频片段

论文标题 VTimeLLM: Empower LLM to Grasp Video Moments VTimeLLM&#xff1a;赋能大语言模型理解视频片段 论文链接&#xff1a; VTimeLLM: Empower LLM to Grasp Video Moments论文下载 论文作者 Bin Huang, Xin Wang, Hong Chen, Zihan Song, Wenwu Zhu (Tsinghua Un…

wujie无界微前端框架初使用

先说一下项目需求&#xff1a;将单独的四套系统的登录操作统一放在一个入口页面进行登录&#xff0c;所有系统都使用的是vue3&#xff0c;&#xff08;不要问我为啥会这样设计&#xff0c;产品说的客户要求&#xff09; 1.主系统下载wujie 我全套都是vue3&#xff0c;所以直接…

ceph文件系统

ceph文件系统&#xff1a;高度可扩展&#xff0c;分布式的存储文件系统&#xff0c;旨在提高性能&#xff0c;高可靠性和高可用的对 象存储&#xff0c;块存储&#xff0c;文件系统的存储。使用分布式的算法保证数据的高可用和一致性。 ceph的组件 1、MON&#xff1a;ceph m…

Django的runserver

当年执行 python manage runserver命令时 1. 先执行 runserver 中的 handle方法 2. 执行 self.run()方法 3. 执行 self.inner_run() 3.1 inner_run 下 run方法的封装 3.1.1 接着看 handle 怎么来的 封装了一个方法 接着找返回函数 3.1.2在 basehttp 下 3.1.3 get_wsgi_appl…

开源AI智能名片2+1链动模式S2B2C商城小程序在商业流量获取中的应用研究

摘要&#xff1a; 随着互联网技术的迅猛发展&#xff0c;商业流量的获取已成为企业市场竞争中的关键环节。传统意义上的“客流量”在互联网语境下被赋予了新的内涵&#xff0c;即“商业流量”&#xff0c;其本质依然指向用户。在当前线上线下融合的商业环境中&#xff0c;流量…