JS继承与原型、原型链
在 JavaScript 中,继承是实现代码复用和构建对象关系的重要概念。本文将讨论原型链继承、构造函数继承以及组合继承等几种常见的继承方式,并提供相应的示例代码,并分析它们的特点、优缺点以及适用场景。
在开始讲解 JavaScript 的继承方式之前,我们先来详细解释一下原型(prototype)、构造函数(constructor)和实例对象(instance)这三个概念。因为只有对它们有清晰的理解,才能更好地理解和应用JavaScript的继承机制。现在我们将分别介绍它们的含义和它们之间的关系。
建议点赞收藏本文章,以便日后复习~~
原型、构造函数、实例对象

在 JavaScript 中,原型(prototype)、构造函数(constructor)和实例对象(instance)是面向对象编程中的重要概念,并且它们之间存在着紧密的关系。
- 原型(prototype): 原型是JavaScript中对象之间关联的一种机制。每个JavaScript对象(除了 null 和 undefined)都有一个原型对象,它包含了对象的属性和方法。当我们访问一个对象的属性或方法时,如果对象本身没有定义该属性或方法,JavaScript引擎会通过原型链向上查找,直到找到对应的属性或方法为止。同理,原型链是由对象的原型对象构成的链式结构,通过这种机制,对象可以继承原型对象的属性和方法。
- 构造函数(constructor): 构造函数是用于创建对象的函数。在JavaScript中,我们可以通过定义一个函数并使用
new关键字来创建对象的实例。构造函数定义了对象的初始状态和行为,并且可以在创建实例时对其进行初始化。构造函数可以包含属性和方法,并且可以使用this关键字引用要创建的实例对象。 - 实例对象(instance): 实例对象是通过构造函数创建的对象,它具有构造函数定义的属性和方法。每个实例对象都是独立的,它们可以根据需要修改自己的属性值,并且可以调用构造函数中定义的方法。实例对象通过原型链与构造函数的原型对象关联在一起,从而实现属性和方法的继承。
function Animal(name) { // 构造函数(自带原型对象)this.name = name || 'Animal'; // 属性
}Animal.prototype.eat = function(food) { // 方法console.log(this.name + '正在吃:' + food);
};var animal = new Animal('Tom'); // 实例对象animal.eat('猫粮')
它们之间的关系如下:
- 每个构造函数都有一个原型对象(prototype),构造函数的原型对象包含了构造函数定义的属性和方法。
- 通过构造函数创建的每个实例对象都有一个内部属性(Prototype),它指向构造函数的原型对象。这个属性在浏览器中通常可以通过
__proto__访问(某些浏览器不支持)。 - 实例对象可以访问构造函数原型对象中的属性和方法。因为它们通过原型链与原型对象关联在一起,如果实例对象访问的属性或方法在自身中找不到,JavaScript引擎会自动沿着原型链向上查找,直到找到对应的属性或方法。
- 当我们修改实例对象的属性时,它会在自身中创建一个与原型对象中同名属性的副本,并在之后的访问中直接使用该副本,而不会影响原型对象中的属性。
- 当我们调用实例对象的方法时,JavaScript引擎会优先在实例对象中查找对应的方法,如果找不到则会继续沿着原型链向上查找,直到找到对应的方法。
什么是JavaScript继承
JavaScript继承是指在前端开发中,使用JavaScript实现对象之间属性和方法的继承关系。继承是面向对象编程的重要概念,它允许我们创建基于现有对象的新对象,并在新对象中拥有原有对象的属性和方法。
在JavaScript中,继承是通过原型链来实现的。每个对象都有一个原型对象,它包含对象的属性和方法。当我们访问一个对象的属性或方法时,如果对象本身没有定义该属性或方法,JavaScript引擎会通过原型链向上查找,直到找到对应的属性或方法为止。这种原型链的查找机制使得对象之间可以共享属性和方法,从而实现继承的效果。

除了原型链继承外,JavaScript还提供了其他几种实现继承的方式,如构造函数继承、组合继承等。在开发中,继承通常用于构建对象之间的关系,使得子类可以共享父类的属性和方法,并有能力添加自己的特定属性和方法。这样可以减少重复的代码编写,提高开发效率和代码的可维护性。
接下来我们详细介绍这些继承方式的原理和使用方法,并提供相应的代码示例。
JavaScript继承方式
1、原型链继承
原型链继承是一种基于原型的继承方式,它通过将父类的实例作为子类的原型来实现继承关系。具体实现如下:
function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat() {Animal.call(this);
}Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
Cat.prototype.name = 'Tom';var cat = new Cat();
原型链继承的特点包括:
- 实例既是子类的实例,也是父类的实例,继承关系非常纯粹。
- 子类可以访问父类新增的原型方法和属性。
- 实现简单,易于理解和实现。
原型链继承的缺点:
- 子类无法在构造器中新增属性和方法,只能在实例化后添加。
- 无法实现多继承。
- 所有实例共享来自原型对象的属性,包括引用属性。
原型链继承适用于简单的继承关系和单一继承需求的场景。
2、构造继承
构造继承通过在子类构造函数中调用父类构造函数,复制父类的实例属性给子类。具体实现如下:
function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat(name) {Animal.call(this, name);
}var cat = new Cat();
构造继承的特点包括:
- 解决了原型链继承中子类实例共享父类引用属性的问题。
- 可以在创建子类实例时向父类传递参数。
- 支持多继承,可以调用多个父类构造函数。
构造继承的缺点:
- 子类实例并不是父类的实例,只是子类的实例。
- 无法继承父类的原型属性和方法。
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能。
构造继承适用于需要继承实例属性、避免引用属性共享以及多继承的场景。
3、实例继承
实例继承通过为父类实例添加新特性,并将其作为子类实例返回。具体实现如下:
function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat(name) {var instance = new Animal();instance.name = name || 'Tom';return instance;
}var cat = new Cat();
实例继承的特点包括:
- 不限制调用方式,无论是
new 子类()还是子类(),返回的对象具有相同的效果。
实例继承的缺点:
- 实例是父类的实例,而不是子类的实例。
- 不支持多继承。
实例继承适用于灵活的对象创建需求,可以根据不同情况返回不同的实例。
4、拷贝继承
拷贝继承通过复制父类的属性和方法给子类实现继承。具体实现如下:
function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat(name) {Animal.call(this, name);
}for (var p in Animal.prototype) {if (Animal.prototype.hasOwnProperty(p)) {Cat.prototype[p] = Animal.prototype[p];}
}Cat.prototype.constructor = Cat;
var cat = new Cat();
拷贝继承的特点包括:
- 支持多继承。
拷贝继承的缺点:
- 效率较低,内存占用高,因为需要拷贝父类的属性。
- 无法获取父类的不可枚举方法。
拷贝继承适用于多继承的场景,但要注意性能和不可枚举方法的问题。
5、组合继承(原型继承+构造继承)
组合继承结合了原型继承和构造继承的优点,通过调用父类构造函数来继承父类的属性,并将父类实例作为子类原型,实现函数复用。具体实现如下:
function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat(name) {Animal.call(this, name);
}Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;var cat = new Cat();
组合继承的特点包括:
- 继承父类实例属性和方法。
- 继承父类原型属性和方法。
- 既是父类的实例,也是子类的实例。
组合继承的缺点:
- 调用了两次父类构造函数,影响性能。
组合继承适用于大多数场景,是一种常用的继承方式。
6、寄生组合继承
寄生组合继承是对组合继承的优化,通过寄生方式避免了两次调用父类构造函数,从而减少了实例化时的重复操作。具体实现如下:
function Animal(name) {this.name = name || 'Animal';
}Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food);
};function Cat(name) {Animal.call(this, name);
}function inheritPrototype(subType, superType) {var prototype = Object.create(superType.prototype);prototype.constructor = subType;subType.prototype = prototype;
}inheritPrototype(Cat, Animal);var cat = new Cat();
寄生组合继承的特点包括:
- 实现简单,堪称完美。
寄生组合继承没有明显的缺点,是一种高效且可靠的继承方式。
结语
我们可以根据具体需求选择适合的继承方式。每种继承方式都有自己的优缺点和适用场景,因此我们应根据实际情况进行选择和灵活运用。
相关文章:
JS继承与原型、原型链
在 JavaScript 中,继承是实现代码复用和构建对象关系的重要概念。本文将讨论原型链继承、构造函数继承以及组合继承等几种常见的继承方式,并提供相应的示例代码,并分析它们的特点、优缺点以及适用场景。 在开始讲解 JavaScript 的继承方式之…...
C#基础知识总结
C语言、C和C#的区别 ✔ 面向对象编程(OOP): C 是一种过程化的编程语言,它不直接支持面向对象编程。然而,C 是一种支持 OOP 的 C 的超集,它引入了类、对象、继承、多态等概念。C# 是完全面向对象的ÿ…...
机器学习模型——决策树
决策树的定义: 决策树利用树形数据结构来展示决策规则和分类结果,它是一种归纳学习算法,可以将复杂数据转化为可以预测未知数据的模型。每一条从根节点到叶节点的路径都代表一条决策规则。 决策树内的一些重要名词: 信息熵&am…...
【HTML】制作一个简单的三角形动态图形
目录 前言 开始 HTML部分 CSS部分 效果图 总结 前言 无需多言,本文将详细介绍一段HTML和CSS代码,具体内容如下: 开始 首先新建文件夹,创建两个文本文档,其中HTML的文件名改为[index.html],CSS的文件名…...
Acwing.504 转圈游戏(带取余的快速幂)
题目 n个小伙伴(编号从 0到 n−1)围坐一圈玩游戏。 按照顺时针方向给 n个位置编号,从 0到 n−1。 最初,第 0号小伙伴在第 0号位置,第 1号小伙伴在第 1号位置,…,依此类推。 游戏规…...
pair作为unordered_map的key报错
问题 pair作为unordered_map的key报错,编译时会报错 原因 因为pair没有哈希函数 解决方法 定义哈希函数 template <typename T> inline void hash_combine(std::size_t &seed, const T &val) {seed ^ std::hash<T>()(val) 0x9e3779b9 (…...
Windows提权—数据库提权-mysql提权mssql提权Oracle数据库提权
目录 Windows 提权—数据库提权一、mysql提权1.1 udf提权1.1.2 操作方法一 、MSF自动化--UDF提权--漏洞利用1.1.3 操作方法二、 手工导出sqlmap中的dll1.1.4 操作方法三、 moon.php大马利用 1.2 mof提权1.3 启动项提权1.4 反弹shell 二、MSSQL提权MSSQL提权方法1.使用xp_cmdshe…...
为什么android创建Fragment推荐用newInstance
FullScreenDialogFragment使用newInstance方法不是因为它是一个单例,而是因为这是创建DialogFragment实例并同时提供参数的一种标准模式。这种模式通常称为静态工厂方法模式,在Android开发中被广泛使用,尤其是用于Fragment的实例化。 newIns…...
MyBatis的xml实现方式
1、该项目引入的依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…...
大模型prompt技巧——思维链(Chain-of-Thought)
1、Zero-shot、One-shot、Few-shot 与fintune prompt的时候给出例子答案,然后再让模型回答。 2、zero-shot-CoT “Let’s think step by step”有奇迹效果 3、多数投票提高CoT性能——自洽性(Self-consistency) 多个思维链,然后取…...
内网穿透的应用-如何在Android Termux上部署MySQL数据库并实现无公网IP远程访问
文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备,尽管最初并非设计为服务器,但是随着技术的进步我们可以将Android配置为生产力工具,变成一个随身…...
面试算法-133-区间子数组个数
题目 给你一个整数数组 nums 和两个整数:left 及 right 。找出 nums 中连续、非空且其中最大元素在范围 [left, right] 内的子数组,并返回满足条件的子数组的个数。 生成的测试用例保证结果符合 32-bit 整数范围。 示例 1: 输入ÿ…...
物联网实战--入门篇之(八)嵌入式-空气净化器
目录 一、风扇调速 二、通讯协议 三、净化器运行逻辑 一、风扇调速 单片机是不能直接驱动电机的,因为主芯片的驱动电流比较小(50mA左右),他们之间正常还要有个电机驱动器,常用的有TB6612、L298和L9110等,目前项目用的这个电机它…...
macOS上QT打开麦克风和摄像头的权限问题
同样的代码在Windows上可以轻松操作麦克风和摄像头,特别是用QT这种跨平台的框架。但是对macOS这种权限要求完善的系统还需要进行一些配置,那就是增加Info.plist属性配置文件。如果是之前的早期5.x版本的QTCreator因为使用的是qmake构建系统,估…...
鸿蒙手机cordova-plugin-camera不能拍照和图片不显示问题
鸿蒙手机cordova-plugin-camera不能拍照和图片不显示问题 一、运行环境 1、硬件 手机型号:NOVA 7 系统:HarmonyOS版本 4.0.0 2、软件 android SDK platforms:14.0(API Level 34)、13.0(API Level 33) SDK Build-T…...
Spring源码解析上
spring源码解析 整体架构 defaultListableBeanFactory xmlBeanDefinitionReader 创建XmlBeanFactory 对资源文件进行加载–Resource 利用LoadBeandefinitions(resource)方法加载配置中的bean loadBeandefinitions加载步骤 doLoadBeanDefinition xml配置模式 validationMode 获…...
第九题:最大间隙
题目描述 给定一个序列 a1,a2,⋯ ,an。其中 a1≤a2≤⋯≤an。 相邻两个数之间的差(后一个数减前一个数)称为它们的间隙。 请问序列中最大的间隙值是多少? 输入描述 输入的第一行包含一个整数 n,表示序列的长度。 第二行包含…...
【随笔】Git -- 高级命令(中篇)(七)
💌 所属专栏:【Git】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! 💖 欢迎大…...
可视化大屏 - 项目1
文章目录 技术栈echarts 可视化需求分析代码实现 技术栈 flexible.js rem 实现不同终端下的响应式布局,根据不同屏幕宽度,自适配布局; html中引入index.js,可以改名为flexible.js;默认划分10份,可以自己修…...
Collection与数据结构 链表与LinkedList(三):链表精选OJ例题(下)
1. 分割链表 OJ链接 class Solution {public ListNode partition(ListNode head, int x) {if(head null){return null;//空链表的情况}ListNode cur head;ListNode formerhead null;ListNode formerend null;ListNode latterhead null;ListNode latterend null;//定义…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...
