从0开始学习JavaScript--JavaScript对象继承深度解析

JavaScript中的对象继承是构建灵活、可维护代码的关键部分。本文将深入讨论JavaScript中不同的继承方式,包括原型链继承、构造函数继承、组合继承等,并通过丰富的示例代码展示它们的应用和差异。通过详细解释,大家可以更全面地了解如何在JavaScript中有效地使用对象继承。

原型链继承

原型链继承是JavaScript中最基本的继承方式。这里将深入研究原型链是如何构建的,以及如何通过原型链使对象实现继承。

function Animal(name) {this.name = name;
}Animal.prototype.makeSound = function() {console.log('Some generic sound');
};function Dog(name, breed) {Animal.call(this, name);this.breed = breed;
}Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;Dog.prototype.bark = function() {console.log('Woof! Woof!');
};const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.makeSound(); // 继承自Animal
myDog.bark();      // Dog自有方法

构造函数继承

构造函数继承通过在子类构造函数内部调用父类构造函数来实现继承。这种方式避免了原型链继承的一些问题。

function Animal(name) {this.name = name;
}Animal.prototype.makeSound = function() {console.log('Some generic sound');
};function Cat(name, color) {Animal.call(this, name);this.color = color;
}const myCat = new Cat('Whiskers', 'Gray');
myCat.makeSound(); // Error: myCat.makeSound is not a function

组合继承

组合继承结合了原型链继承和构造函数继承的优点,是一种常用的继承方式。

function Animal(name) {this.name = name;
}Animal.prototype.makeSound = function() {console.log('Some generic sound');
};function Horse(name, color) {Animal.call(this, name);this.color = color;
}Horse.prototype = Object.create(Animal.prototype);
Horse.prototype.constructor = Horse;const myHorse = new Horse('Spirit', 'Brown');
myHorse.makeSound(); // 继承自Animal

原型式继承

原型式继承通过借助现有对象创建新对象,是一种简单的继承方式。

const animal = {makeSound: function() {console.log('Some generic sound');}
};const dog = Object.create(animal);
dog.bark = function() {console.log('Woof! Woof!');
};dog.makeSound(); // 继承自animal
dog.bark();      // dog自有方法

寄生式继承

寄生式继承是在原型式继承的基础上增强对象,可以在对象上添加额外的方法。

function createDog(name) {const dog = Object.create({makeSound: function() {console.log('Some generic sound');}});dog.name = name;dog.bark = function() {console.log('Woof! Woof!');};return dog;
}const myDog = createDog('Buddy');
myDog.makeSound(); // 继承自原型对象
myDog.bark();      // 自有方法

寄生组合式继承

寄生组合式继承是在组合继承的基础上进行优化,避免了调用两次父类构造函数。

function inheritPrototype(subType, superType) {const prototype = Object.create(superType.prototype);prototype.constructor = subType;subType.prototype = prototype;
}function Vehicle(name) {this.name = name;
}Vehicle.prototype.drive = function() {console.log('Vroom!');
};function Car(name, color) {Vehicle.call(this, name);this.color = color;
}inheritPrototype(Car, Vehicle);Car.prototype.honk = function() {console.log('Honk! Honk!');
};const myCar = new Car('Toyota', 'Blue');
myCar.drive(); // 继承自Vehicle
myCar.honk();  // Car自有方法

ES6的Class继承

ES6引入了class语法糖,提供了更清晰、更面向对象的继承方式。

class Animal {constructor(name) {this.name = name;}makeSound() {console.log('Some generic sound');}
}class Bird extends Animal {constructor(name, color) {super(name);this.color = color;}fly() {console.log('I believe I can fly!');}
}const myBird = new Bird('Tweety', 'Yellow');
myBird.makeSound(); // 继承自Animal
myBird.fly();       // Bird自有方法

Symbol与继承

Symbol是ES6引入的一种新的原始数据类型,可以用于创建唯一的标识符。在继承中,Symbol可以用于创建不可枚举的属性。

const animal = {name: 'Generic Animal',
};const key = Symbol('sound');
animal[key] = 'Some generic sound';const dog = Object.create(animal);
dog.bark = function() {console.log(this[key]);
};dog.bark(); // 继承自animal的Symbol属性

混入(Mixin)

混入是一种通过将多个对象的属性和方法合并到一个新对象中的方式,实现了对象的复用。

const canSwim = {swim() {console.log('Swimming!');},
};const canFly = {fly() {console.log('Flying!');},
};function mixin(target, ...sources) {Object.assign(target, ...sources);
}const duck = {};
mixin(duck, canSwim, canFly);duck.swim(); // 来自canSwim
duck.fly();  // 来自canFly

对象继承的性能考虑

在对象继承中,性能是一个重要的考虑因素。选择合适的继承方式可以显著影响代码的执行效率。以下是一些关于性能考虑的建议:

1. 原型链深度

过度的原型链深度会导致原型链查找时间增加,影响性能。尽量保持原型链的简洁,避免过多层次的嵌套。合理使用原型链,确保在维护性和性能之间找到平衡。

2. 构造函数调用

在构造函数继承中,避免不必要的构造函数调用。有些继承方式可能会多次调用父类的构造函数,造成冗余的工作。寻找可以减少构造函数调用次数的优化方法是很重要的。

3. 原型链查找与缓存

对于频繁访问的属性和方法,可以考虑将其缓存到子对象中,避免在原型链上进行多次查找。这可以通过在构造函数中引用父类的方法或属性来实现。

4. Class与原型链

在ES6中引入的class语法糖相比传统原型链继承具有更好的性能。它更直观,而且对引擎的优化更友好。在现代JavaScript开发中,推荐使用class语法糖来实现对象的继承。

5. 延迟加载

某些情况下,可以考虑延迟加载一些不常用的属性或方法,以提高初始加载性能。这可以通过在需要时动态加载相关部分来实现。

6. 使用原生方法

尽量使用原生方法,因为它们通常由JavaScript引擎进行高度优化。避免过度封装或使用过多的抽象层,以确保性能的最佳表现。

在实际项目中,性能优化往往需要根据具体情况进行调整。通过使用工具进行性能分析,可以更准确地找到需要优化的地方。综上所述,选择合适的继承方式并结合性能最佳实践,能够有效提升应用程序的整体性能。

总结

在深入探讨JavaScript对象继承的过程中,不仅理解了各种继承方式的实现机制和优缺点,而且关注了性能方面的考虑。对于性能,强调了避免过度的原型链深度、谨慎处理构造函数调用、合理使用原型链查找与缓存等策略。

了解继承方式的性能影响有助于开发者在实际应用中做出明智的选择。我们推崇使用ES6引入的class语法糖,因为它不仅直观易懂,还对JavaScript引擎的优化更为友好。此外,延迟加载和原生方法的使用也是提高性能的有效手段。

总体而言,通过深入研究JavaScript对象继承,能够更好地权衡继承方式的利弊,选择适合项目需求的方式。性能方面的考虑则为我们提供了优化代码的指导原则,确保我们在维护性和性能之间取得平衡。通过这些理念的应用,能够编写更高效、可维护的JavaScript代码,为项目的成功实施提供坚实的基础。

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

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

相关文章

nodejs+vue+elementui+express青少年编程课程在线考试系统

针对传统线下考试存在的老师阅卷工作量较大,统计成绩数据时间长等问题,实现一套高效、灵活、功能强大的管理系统是非常必要的。该系统可以迅速完成随机组卷,及时阅卷、统计考试成绩排名的效果。该考试系统要求:该系统将采用B/S结构…

【JMeter】使用BeanShell写入内容到文件

一、前言 在我们日常工作中,可能会遇到需要将请求返回的数据写入到文件中。在我们使用JMeter进行性能测试时,就经常能够遇到这种情况。要想达到这种目的,我们一般采取BeanShell后置处理器来将内容写入到文件。 二、提取 在目前大多数的性能…

11.22数电第四次报告

《数字逻辑》实验报告 姓名 贾轲 年级 22 学号 20220669 专业、班级 计算机科学与技术计卓01 实验名称 实验十五 摩尔状态机序列检测器&实验十六 米利状态机序列检测器 实验时间 2023.11.23 实验地点 DS1410 实验成绩 实验性质 □验证性 □设计性 □…

SIFT尺度不变特征变换

SIFT(Scale-Invariant Feature Transform)是一种用于图像处理和计算机视觉中的特征提取和匹配的算法。它的主要优点是对图像的尺度、旋转和亮度变化具有较强的鲁棒性。 基本原理: Scale-space peak selection: Potential location for finding features.Keypoint Localizat…

JMeter之压力测试——混合场景并发

在实际的压力测试场景中,有时会遇到多个场景混合并发的情况,这时就需要设置不同的并发比例对不同场景请求数量的控制,下面提供两种方案。 一、多线程组方案 1.业务场景设计如下:场景A、场景B、场景C,三个场景按照并发…

HNU 练习八 结构体编程题1. 评委打分

【问题描述】 校园卡拉OK比赛设置了7名评委,当一名选手K完歌之后,主持人报出歌手名字后,7位评委同时亮分,按照惯例,去掉一个最高分和一个最低分后,其余5位评委评分总和为该选手的最终得分。 一共有n组选手参…

商用车量产智能驾驶路径思考

1、商用车量产智能驾驶特点 2、量产自动驾驶路径 3、商用车ADAS法规件 4、高等级自动驾驶

oracle impdp 导入元数据表空间异常增大的解决办法

expdp导出的时候指定了contentsmetadata_only只导出元数据,但是在impdp导入到新库的时候,发现新库的表空间增长非常大,其实这个直接就可以想到,应该是大表的initial segment过大导致的 正常impdp,在执行创建表和索引的…

c/c++ 字符 - ‘0‘ 或者 + ‘0‘ 的含义

总的就是说,int0char;char-0int ,但是我们在做题时,这两个式子对数字才有意义,比如 char x50;int y5-0. 而我们平常对字符操作,比如大写字符转小写(char cA->a),只需要cc-Aa,等…

Java LinkedHashMap

LinkedHashMap 继承于 HashMap。在 HashMap 基础上, 维护了一条双向链表, 用来记录存入 Map 中的数据的顺序, 即存储到 Map 中的 key-value 是有序的。 解决了 HashMap 无法顺序访问的和保持插入顺序的问题。 1 LinkedHashMap 的结构定义 LinkedHashMap 是基于 HashMap 的实现…

springboot3.2 整合 mybatis-plus

springboot3.2 整合 mybatis-plus springboot3.2 正式发布了 迫不及待地的感受了一下 结果在整个mybatis-plus 的时候遇到了如下报错 java.lang.IllegalArgumentException: Invalid value type for attribute factoryBeanObjectType: java.lang.String. ____ _ …

华为拆分零部件业务,长安入股,赛力斯接洽中

作者 |德新 编辑 |王博 11月26日,长安汽车官宣与华为在智能汽车零部件业务上的投资与合作: 华为拟成立一家新的公司,并将其在智能汽车解决方案业务上的核心技术和资源注入新公司,长安汽车及关联方有意投资该新公司。 参照目前长…

每日一题--寻找重复数

蝶恋花-王国维 阅尽天涯离别苦, 不道归来,零落花如许。 花底相看无一语,绿窗春与天俱莫。 待把相思灯下诉, 一缕新欢,旧恨千千缕。 最是人间留不住,朱颜辞镜花辞树。 目录 题目描述: 思路分析…

搭建Appium工具环境

1、安装Java Development Kit(JDK) 前往Oracle官网下载JDK。 在https://www.oracle.com/java/technologies/javase-jdk11-downloads.html 找到最新版本的JDK。根据操作系统选择适合的版本,并根据指示下载安装程序。 安装JDK。运行下载的安…

动静分离+多实例实验(nginx+tomcat)

Nginx服务器:192.168.188.14:80 Tomcat服务器1:192.168.188.11:80 Tomcat服务器2:192.168.188.12:8080 192.168.188.12:8081 部署Nginx负载均衡器 关闭防火墙 systemctl stop firewalld setenforce 0 安装依赖 yum -y install pcre-dev…

Java 基础学习(二)运算符与分支流程控制

1 运算符 1.1 运算符概述 1.1.1 运算符概述 运算符是一种告诉计算机执行特定的数学或逻辑等操作的符号。Java运算符号包括:数学运算符、关系运算符、逻辑运算符、赋值运算符号、字符串连接运算符。计算机本质上只能处理数字,处理数字的最常见的方式就…

华夏ERP信息泄露漏漏洞复现 [附POC]

文章目录 华夏ERP信息泄露漏漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 华夏ERP信息泄露漏漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内的相关技术从事非法测试&#x…

好用的基于layui的免费开源后台模版layuimini

发现一个好用的后台模版 基于layui的免费开源后台模版layuimini layuimini - 基于Layui的后台管理系统前端模板 easyadmin开源项目 EasyAdmin是基于ThinkPHP6.0Layui的快速开发的后台管理系统。 演示站点 演示地址:跳转提示(账号:admin&a…

Java实现—数据结构 1.初识集合框架

一、什么是集合框架 Java集合框架,又被称为容器,是定义在java.util包下的一组接口interfaces和其实现类classes 其主要表现为将多个元素element置于一个单元中, 集合框架是由若干个类组成的,每个类的背后就是一种数据结构&…

Jupyter Markdown 插入图片

首先截图 注意 这一步是关键的!! 它需要使用电脑自带的截图,用qq啊vx啊美图秀秀那些都不行哦。 截图之后复制: 然后快捷键粘贴到jupyter里面,它会生成一段代码(没有代码就是说截图形式不对)&a…