当前位置: 首页 > news >正文

JavaScript 中的原型和原型链

JavaScript 中的原型和原型链也是一个相对较难理解透彻的知识点,下面结合详细例子来进行说明:

一、原型的概念

在 JavaScript 中,每个函数都有一个 prototype 属性,这个属性指向一个对象,这个对象就是所谓的 “原型对象”。当通过构造函数创建一个新的实例对象时,该实例对象会自动拥有一个指向构造函数原型对象的内部属性(在大多数浏览器中可以通过 proto 来访问这个内部属性,虽然它并非标准属性,但方便理解)。
例如:

function Person(name, age) {this.name = name;this.age = age;
}Person.prototype.sayHello = function () {console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
};let john = new Person('John', 30);
john.sayHello(); 
// 输出:Hello, my name is John and I'm 30 years old.

在这个例子中:
首先定义了一个 Person 函数作为构造函数,用来创建 Person 类型的实例。
然后给 Person 函数的 prototype 属性添加了一个 sayHello 方法。
当通过 new Person(‘John’, 30) 创建了 john 这个实例后,john 本身并没有 sayHello 这个方法的定义,但是它可以通过内部的 proto 属性(指向 Person.prototype)找到并调用 sayHello 方法。

二、原型链的形成

当在一个对象上访问某个属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 就会自动沿着它的原型链去查找。原型链就是由对象的 proto 属性连接起来的一系列对象。
继续上面的例子,假设我们有这样一个情况:

function Employee(name, age, department) {Person.call(this, name, age);this.department = department;
}Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;Employee.prototype.sayDepartment = function () {console.log(`I work in the ${this.department} department.`);
};let jane = new Employee('Jane', 25, 'Engineering');
jane.sayHello(); 
// 输出:Hello, my name is Jane and I'm 25 years old.
jane.sayDepartment(); 
// 输出:I work in the Engineering department.

在这个例子中:
首先定义了 Employee 函数作为构造函数来创建 Employee 类型的实例,并且在构造函数内部通过 Person.call(this, name, age) 调用了 Person 构造函数,以便让 Employee 实例继承 Person 实例的 name 和 age 属性。
然后通过 Employee.prototype = Object.create(Person.prototype) 让 Employee 的原型对象继承自 Person 的原型对象,这样 Employee 实例就可以沿着原型链找到 Person 原型对象上的方法(如 sayHello)。同时,重新设置了 Employee.prototype.constructor 为 Employee,以保证构造函数的正确性。
最后给 Employee 原型对象添加了 sayDepartment 方法。
当我们在 jane(Employee 实例)上调用 sayHello 方法时,jane 本身没有 sayHello 方法,它会通过自己的 proto 属性(此时指向 Employee.prototype)找不到,就继续沿着 Employee.prototype 的 proto(因为 Employee.prototype = Object.create(Person.prototype),所以 Employee.prototype.proto 指向 Person.prototype)找到 Person.prototype 上的 sayHello 方法并调用。

三、原型链的查找顺序

为了更清楚地展示原型链的查找顺序,我们再看一个例子:

function Animal() {}
Animal.prototype.eat = function () {console.log('Eating...');
};function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.bark = function () {console.log('Woof!');
};let myDog = new Dog();
myDog.eat(); 
// 输出:Eating...
myDog.bark(); 
// 输出:Woof!// 查看原型链
console.log(myDog.__proto__ === Dog.prototype); 
// 输出:true
console.log(myDog.__proto__.__proto__ === Animal.prototype); 
// 输出:true
console.log(myDog.__proto__.__proto__.__proto__ === Object.prototype); 
// 输出:true
console.log(myDog.__proto__.__proto__.__proto__.__proto__ === null); 
// 输出:true

在这个例子中:
定义了 Animal 函数和其原型对象上的 eat 方法。
定义了 Dog 函数,并让其原型对象继承自 Animal 原型对象,同时在 Dog 原型对象上添加了 bark 方法。
当创建了 myDog 这个 Dog 实例后,在 myDog 上调用 eat 方法时,首先 myDog 本身没有 eat 方法,它会沿着原型链查找。先通过 myDog.proto(指向 Dog.prototype)找不到,再通过 myDog.proto.proto(指向 Animal.prototype)找到并调用 eat 方法。同样,调用 bark 方法时,在 myDog 本身找不到,通过 myDog.proto 就能找到并调用。
从 myDog 的原型链可以看出,查找顺序是先在实例本身查找,然后沿着 proto 指向的对象依次查找,一直到 Object.prototype,最后 Object.prototype.proto 为 null,表示原型链的尽头。

四、原型和原型链的难点

概念的抽象性:原型和原型链涉及到对象、函数、构造函数、原型对象等多个概念的相互关系,理解起来比较抽象。例如,要清楚地区分函数的 prototype 属性和实例对象的 proto 属性,以及它们之间是如何相互作用来实现属性和方法的继承的,这对于初学者来说并不容易。
复杂的继承关系:当涉及到多层继承时,如上面例子中的 Employee 继承自 Person,再加上可能还有更多层的继承关系,要准确把握每个实例沿着原型链查找属性和方法的路径以及如何正确设置继承关系(比如通过 Object.create 等方式),这需要对原型链的机制有深入的理解。
与其他语言的差异:对于有其他编程语言背景的开发者来说,JavaScript 的原型继承方式与基于类的继承(如 Java、C++ 等)有很大的不同。在基于类的继承中,继承关系通常是通过类的定义和关键字(如 extends)来明确规定的,而 JavaScript 是通过原型和原型链这种相对更灵活但也更抽象的方式来实现继承的,所以习惯了类继承的开发者可能会觉得难以适应。
原型和原型链在 JavaScript 中是非常重要的概念,虽然理解起来有一定难度,但掌握它们对于深入理解 JavaScript 的对象系统以及编写高效、灵活的代码至关重要。

相关文章:

JavaScript 中的原型和原型链

JavaScript 中的原型和原型链也是一个相对较难理解透彻的知识点,下面结合详细例子来进行说明: 一、原型的概念 在 JavaScript 中,每个函数都有一个 prototype 属性,这个属性指向一个对象,这个对象就是所谓的 “原型对…...

数组变换(两倍)

数组变换 以最大元素为基准元素,判读其他元素能否通过 x 2 成为最大值! 那么怎么判断呢: max % arr[i] 0arr[i] * 2 ^n max int x 2 ^ n max / arr[i] 3.只需判断 这个 x 是不是 2 的 n 次放就可以了! 判断 是否为 2 的 n 次 …...

GBN协议、SR协议

1、回退N步(Go-Back-N,GBN)协议: 总结: GBN协议的特点: (1)累计确认机制:当发送方收到ACKn时,表明接收方已正确接收序号为n以及序号小于n的所有分组,发送窗…...

三维扫描检测仪3d扫描测量尺寸-自动蓝光测量

在现代工业及生产过程中,精确、高效的尺寸检测是保证产品质量、提升生产效率的关键因素。 红、蓝光测量,以其高精度、高效率和非接触式的特点,在工业及生产中发挥着越来越重要的作用。蓝光测量技术利用蓝色激光光源,通过扫描被测…...

大模型翻译能力评测

1. 背景介绍 随着自然语言处理技术的飞速发展,机器翻译已经成为一个重要的研究领域。近年来,基于大模型的语言模型在机器翻译任务上取得了显著的进展。这些大模型通常具有数亿甚至数千亿的参数,能够更好地理解和生成自然语言。 但是&#xf…...

MySQL隐式转换造成索引失效

一、什么是 MySQL 的隐式转换? MySQL 在执行查询语句时,有时候会自动帮我们进行数据类型的转换,这个过程就是隐式转换。比如说,我们在一个 INT 类型的字段上进行查询,但是传入的查询条件却是字符串类型的值&#xff0c…...

SuperMap Objects组件式GIS开发技术浅析

引言 随着GIS应用领域的扩展,GIS开发工作日显重要。一般地,从平台和模式上划分,GIS二次开发主要有三种实现方式:独立开发、单纯二次开发和集成二次开发。上述的GIS应用开发方式各有利弊,其中集成二次开发既可以充分利…...

多组数输入a+b:JAVA

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 输入描述: 输入包含多组数据,每组数据输入一行,包含两个整数 输出描述: 对于每组数据输出一行包含一个整数表示两个整数的和 代码: import java.util.Scanner; pu…...

R语言结构方程模型(SEM)在生态学领域中的应用

目录 专题一、R/Rstudio简介及入门 专题二、结构方程模型(SEM)介绍 专题三:R语言SEM分析入门:lavaan VS piecewiseSEM 专题四:SEM全局估计(lavaan)在生态学领域高阶应用 专题五&#xff1…...

架构-微服务-服务调用Dubbo

文章目录 前言一、Dubbo介绍1. 什么是Dubbo 二、实现1. 提供统一业务api2. 提供服务提供者3. 提供服务消费者 前言 服务调用方案--Dubbo‌ 基于 Java 的高性能 RPC分布式服务框架,致力于提供高性能和透明化的 RPC远程服务调用方案,以及SOA服务治理方案。…...

【SpringBoot问题】IDEA中用Service窗口展示所有服务及端口的办法

1、调出Service窗口 打开View→Tool Windows→Service,即可显示。 2、正常情况应该已经出现SpringBoot,如下图请继续第三步 3、配置Service窗口的项目启动类型。微服务一般是Springboot类型。所以这里需要选择一下。 点击最后一个号,点击Ru…...

OpenCV 图像轮廓查找与绘制全攻略:从函数使用到实战应用详解

摘要:本文详细介绍了 OpenCV 中用于查找图像轮廓的 cv2.findContours() 函数以及绘制轮廓的 cv2.drawContours() 函数的使用方法。涵盖 cv2.findContours() 各参数(如 mode 不同取值对应不同轮廓检索模式)及返回值的详细解析,搭配…...

电机驱动MCU介绍

电机驱动MCU是一种专为电机控制设计的微控制器单元,它集成了先进的控制算法和高性能的功率输出能力。 电机驱动MCU采用高性能的处理器核心,具有快速的运算速度和丰富的外设接口。它内置了专业的电机控制算法,包括PID控制、FOC(Fi…...

人工智能学习框架详解及代码使用案例

人工智能学习框架详解及代码使用案例 人工智能(AI)学习框架是构建和训练AI模型的基础工具,它们提供了一组预定义的算法、函数和工具,使得开发者能够更快速、更高效地构建AI应用。本文将深入探讨人工智能学习框架的基本概念、分类、优缺点、选择要素以及实际应用,并通过代…...

修改Textview中第一个字的字体,避免某些机型人民币¥不显示

在 Android 中,系统提供了三种常用的字体类型,分别是: Serif(衬线字体): 这种字体有明显的衬线或笔画末端装饰,通常用于印刷品和书籍,给人一种正式和优雅的感觉。示例:Typeface.SERI…...

彻底理解quadtree四叉树、Octree八叉树 —— 点云的空间划分的标准做法

1.参考文章: (1)https://www.zhihu.com/question/25111128 这里面的第一个回答,有一幅图: 只要理解的四叉树的构建,对于八叉树的构建原理类比方法完全一样:对于二维平面内的随机分布的这些点&…...

Python时间序列优化之道滑动与累积窗口的应用技巧

大家好,在时间序列数据处理中,通常会进行滑动窗口计算(rolling)和累积窗口计算(expanding)等操作,以便分析时间序列的变化趋势或累积特征。Pandas提供的rolling和expanding函数提供了简单、高效的实现方式,特别适用于金融、气象、…...

Buffered 和 BuffWrite

Buffered和BuffWrite是Java IO包中的两个类,用于提高IO操作的效率。 Buffered是一个缓冲区类,可以将一个InputStream或者一个Reader包装起来,提供了一定的缓冲区大小,可以一次读取多个字节或字符,减少了读取的次数&am…...

【娱乐项目】基于cnchar库与JavaScript的汉字查询工具

Demo介绍 利用了 cnchar 库来进行汉字相关的信息查询,并展示了汉字的拼音、笔画数、笔画顺序、笔画动画等信息用户输入一个汉字后,点击查询按钮,页面会展示该汉字的拼音、笔画数、笔画顺序,并绘制相应的笔画动画和测试图案 cnchar…...

泷羽sec-蓝队基础之网络七层杀伤链 (下)学习笔记

声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来&#xf…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

AspectJ 在 Android 中的完整使用指南

一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)​现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...