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)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
javascript闭包如何实现状态机
上一篇 2025年12月20日 07:27:36
javascript闭包怎样缓存复杂计算结果
下一篇 2025年12月20日 07:27:46

相关推荐

  • 如何基于Swoole开发自定义框架?

    基于swoole开发自定义框架可以通过以下步骤实现:1. 创建核心app类,初始化swoole服务器并定义回调函数;2. 实现路由功能,使用router类处理请求分发;3. 添加中间件支持,使用middleware类处理请求;4. 集成异步数据库操作,使用swoole的mysql协程客户端;5. 实…

    2026年9月21日
    000
  • 万人同时在线抽奖活动架构

    万人同时在线抽奖活动的系统架构应采用微服务架构、分布式数据库、redis缓存、区块链存储结果,并使用负载均衡和异步处理技术。具体包括:1.采用微服务架构和分布式数据库(如tidb)保证系统稳定性和可扩展性;2.使用redis处理抽奖逻辑,确保高效和随机性;3.将结果存入区块链,保证透明度和可验证性;…

    2026年9月21日
    000
  • 自定义组件(Component)的开发方法

    开发自定义组件的步骤包括:1. 使用html和css定义组件结构和样式;2. 用javascript实现动态效果和状态管理;3. 确保跨浏览器和设备兼容性;4. 采用模块化设计和外部状态管理工具;5. 进行性能优化和测试驱动开发。通过这些步骤,可以创建出优雅且高效的自定义组件,提升用户体验。 在开发…

    2026年9月21日
    000
  • mysql如何排查磁盘IO瓶颈

    首先检查系统级磁盘IO,使用iostat、iotop等工具分析磁盘利用率和进程IO行为;再通过MySQL慢查询日志、sys.schema视图及SHOW ENGINE INNODB STATUS排查高IO消耗的SQL与内部等待事件;接着评估innodb_buffer_pool_size、innodb_…

    2026年9月21日
    000
  • 协程调试与性能分析工具

    我们需要协程调试和性能分析工具是因为协程的异步特性使得传统工具难以应对调试和性能优化挑战。1) pycharm 适合基本调试,但处理大量协程时可能变慢。2) aiodebug 适用于检测协程问题,但会增加性能开销。3) asyncio-profiler 用于分析协程性能,但可能难以解读大量协程的结果…

    2026年9月21日
    100
  • Linux如何创建新用户并设置初始密码

    Linux如何创建新用户并设置初始密码Linux如何创建新用户并设置初始密码Linux如何创建新用户并设置初始密码Linux如何创建新用户并设置初始密码

    创建新用户并设初始密码需用useradd加passwd命令,如sudo useradd -m -s /bin/bash devuser创建用户,sudo passwd devuser设置密码;通过sudo usermod -aG sudo devuser赋予sudo权限;密码策略应包含长度、复杂度、…

    2026年9月21日 用户投稿
    100
  • Java中浮点数比较的陷阱:理解double类型的不精确性与正确比较方法

    java中`double`类型因其二进制浮点表示的固有不精确性,即使在相同java版本和架构下,也可能在不同环境中产生微小的数值差异。直接使用`==`比较浮点数是不可靠的,因为它无法容忍这些细微的舍入误差。正确的做法是采用基于容差(epsilon)的比较方法,通过判断两数之差的绝对值是否小于一个预设…

    2026年9月21日
    200
  • 如何避免协程中的共享资源竞争?

    避免协程中的共享资源竞争可以通过以下方法:1. 使用锁(locks),如互斥锁或读写锁,确保同一时间只有一个协程访问共享资源。2. 采用无锁数据结构(lock-free data structures),通过原子操作和cas操作提高并发性能。3. 实施消息传递(message passing),通过…

    2026年9月21日
    100
  • Jedis jsonGet 方法返回字节数组值末尾出现 .0 的处理策略

    当使用jedis客户端的`jsonget`方法从redis获取json数据时,如果其中包含字节数组(如xml字符串的字节表示),可能会因底层json库(如gson或org.json)的默认行为,导致数字被统一上转型为`double`类型,从而在输出中显示`.0`后缀。本文将深入探讨此问题产生的原因,…

    2026年9月21日
    300
  • Laravel与Vue.js/React前端框架集成

    laravel可以与vue.js或react集成。1) 使用命令“php artisan preset vue”或“php artisan preset react”设置开发环境。2) 在laravel视图中引入编译后的javascript文件。3) 通过laravel的api路由和前端框架的htt…

    2026年9月21日
    100
  • mysql索引的类型和作用有哪些

    MySQL常见索引类型包括:1. 普通索引用于加速查询;2. 唯一索引确保列值唯一;3. 主键索引为唯一非空且自动创建聚簇索引;4. 聚簇索引决定数据物理存储顺序,每表仅一个;5. 非聚簇索引保存主键值,需回表查询;6. 覆盖索引避免回表提升性能;7. 联合索引遵循最左前缀原则;8. 全文索引支持文…

    2026年9月21日
    100
  • Linux如何查看命令别名alias使用方法

    直接输入 alias 命令可列出当前会话所有别名,如需查看特定命令是否为别名可用 type 命令;别名通过简化常用命令提升效率并减少错误,临时别名在当前会话生效,永久别名需写入 ~/.bashrc 或 ~/.zshrc 文件,删除则用 unalias 命令;别名适用于简单命令替换,函数支持参数与逻辑…

    2026年9月21日
    100
  • 如何设计统一的API响应格式?

    统一的api响应格式可以通过以下步骤设计:1. 使用包含状态码、消息和数据的基本结构;2. 定义标准的错误码和消息;3. 加入版本字段以支持版本控制和扩展性。这样可以提高api的可读性、简化错误处理和增强可扩展性,提升整体开发效率和用户体验。 统一的API响应格式是构建可靠和用户友好的API的关键。…

    2026年9月21日
    100
  • 为什么VSCode的语法高亮有时会失效?

    语法高亮失效通常由语言模式识别错误、扩展冲突或配置问题导致。1. 检查右下角语言模式并手动切换为正确类型,确保文件有正确扩展名;2. 禁用近期安装的扩展或以 code –disable-extensions 启动排查冲突;3. 切换至默认主题并检查 settings.json 是否覆盖颜…

    2026年9月21日
    600
  • Linux命令行如何查看登录用户

    Linux命令行如何查看登录用户Linux命令行如何查看登录用户Linux命令行如何查看登录用户Linux命令行如何查看登录用户

    答案是 who、w 和 users 命令用于查看Linux系统登录用户,其中 who 显示登录用户及终端信息,w 还显示用户正在执行的命令和系统负载,users 仅输出用户名列表。 在Linux命令行下,要查看当前系统上有哪些用户登录,最直接、最常用的命令包括 who 、 w 和 users 。它们…

    2026年9月21日 用户投稿
    200
  • Windows系统下的兼容性问题

    windows兼容性问题严重是因为系统演进快、硬件和软件环境多样。处理此问题需:1.了解目标系统版本和配置;2.使用低版本api或兼容性模式;3.检测操作系统版本并调整程序行为;4.避免依赖特定版本的库,提供多版本安装包;5.考虑硬件依赖性,提供备选方案;6.进行跨版本性能测试和优化。 在Windo…

    2026年9月21日
    100
  • Linux如何限制用户执行特定命令

    Linux如何限制用户执行特定命令Linux如何限制用户执行特定命令Linux如何限制用户执行特定命令Linux如何限制用户执行特定命令

    首选sudo进行命令限制,因其灵活且可审计;通过visudo配置精确的用户权限,结合白名单、命令别名和!语法实现允许或拒绝特定命令;同时防范绕过手段如全路径执行、间接调用、脚本执行等,需多层防御并辅以日志监控。 在Linux环境中,限制用户执行特定命令,最直接有效且灵活的方法通常是利用 sudo 权…

    2026年9月21日 用户投稿
    200
  • mysql如何理解索引选择性

    索引选择性是衡量索引效率的关键指标,定义为索引列不同值数量与总行数的比值,范围在0到1之间。越接近1,数据唯一性越高,索引过滤能力越强,查询性能越好。例如主键列选择性为1,而性别列因重复值多选择性极低。MySQL优化器会优先选择高选择性索引以缩小搜索范围,提高执行效率。可通过SELECT COUNT…

    2026年9月21日
    100
  • Linux如何查看sudo执行的历史记录

    Linux如何查看sudo执行的历史记录Linux如何查看sudo执行的历史记录Linux如何查看sudo执行的历史记录Linux如何查看sudo执行的历史记录

    要追溯sudo执行的命令,需查看系统日志或配置sudo日志;在Ubuntu/Debian中查/var/log/auth.log,CentOS/RHEL中查/var/log/secure,或使用journalctl _COMM=sudo筛选;通过配置/etc/sudoers中的Defaults log…

    2026年9月21日 用户投稿
    300
  • 如何模拟用户登录状态进行测试?

    模拟用户登录状态是为了测试系统功能和安全性。1.在开发初期帮助发现和修复问题。2.测试不同用户权限下的功能访问。方法包括:1.直接操作session或cookie。2.使用测试框架如junit或testng。3.模拟api请求。 模拟用户登录状态进行测试是确保软件系统用户体验和安全性的关键步骤。无论…

    2026年9月21日
    300

发表回复

登录后才能评论
关注微信