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 的对象系统以及编写高效、灵活的代码至关重要。

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

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

相关文章

【Java基础面试题001】Java中序列化和反序列化是什么?

在Java中,序列化和反序列化是用于将对象的状态保存和恢复的重要机制。 序列化 是将Java对象转换为字节流的过程,这样Java对象才可以网络传输、持久化存储还有缓存。Java提供了java.io.Serializable接口来支持序列化,只要类实现了这个接口&a…

前端学习week8——vue.js

Vue.js 基础 Vue 核心概念:了解 Vue 的响应式系统、组件、指令(如 v-if、v-for、v-model 等)。Vue 项目管理:学习 Vue CLI 或 Vite,掌握项目创建、管理和打包。推荐学习顺序:Vue 基础 → 组件化开发 → Vu…

Excel如何限制单元格内可选择的下拉框内容?

先选择想要的表格区域: 如果想要选中如下所示:C2格子及其下面所有的格子(则:点击一下C2格子,然后按一下键盘:SHIFT CTRL ↓) 然后在【sheet2】表,先填写好下拉框可选择的内容&am…

uniapp实现列表页面,实用美观

咨询列表页面 组件 <template><view><view class"news_item" click"navigator(item.id)" v-for"item in list" :key"item.id"><image :src"item.img_url"></image><view class"righ…

Linux学习笔记11 系统启动初始化,服务和进程管理(下)

前文 前文介绍了系统启动初始化程序&#xff0c;介绍了systemd的基础知识。这里主要看一下我们systemd的单元管理和常用的命令以及示例。 Linux学习笔记10 系统启动初始化&#xff0c;服务和进程管理&#xff08;上&#xff09;-CSDN博客 systemd单元管理 启动服务 这很常…

哈希表,哈希桶的实现

哈希概念 顺序结构以及平衡树中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在查找一个元素 时&#xff0c;必须要经过关键码的多次比较。顺序查找时间复杂度为O(N)&#xff0c;平衡树中为树的高度&#xff0c;即 O(logN)&#xff0c;搜索的效率取决…

Maven install java heap space

Maven install java heap space 打包报错 Maven install java heap space 解决&#xff1a; vm option: -Xms1024m -Xmx1024m如果 vm配置了&#xff0c;还是一样报错&#xff0c;就重新选择JRE看看是否正确&#xff0c;idea会默认自己的环境&#xff0c;导致设置vm无效&…

aws(学习笔记第十五课) 如何从灾难中恢复(recover)

aws(学习笔记第十五课) 如何从灾难中恢复 学习内容&#xff1a; 使用CloudWatch对服务器进行监视与恢复区域(region)&#xff0c;可用区(available zone)和子网(subnet)使用自动扩展(AutoScalingGroup) 1. 使用CloudWatch对服务器进行监视与恢复 整体架构 这里模拟Jenkins Se…

【Maven】依赖管理

4. Maven的依赖管理 在 Java 开发中&#xff0c;项目的依赖管理是一项重要任务。通过合理管理项目的依赖关系&#xff0c;我们可以有效的管理第三方库&#xff0c;模块的引用及版本控制。而 Maven 作为一个强大的构建工具和依赖管理工具&#xff0c;为我们提供了便捷的方式来管…

go语言的成神之路-筑基篇-中间件

目录 单个Gin中间件 中间件简要概述 一、中间件的定义&#xff1a; 二、中间件的使用&#xff1a; 效果展示 多个Gin中间件 示例 Abort阻止后续处理函数 执行流程图 return直接返回 执行流程图 全局注册中间件 注意事项 单个Gin中间件 中间件简要概述 在 gin 框架中…

Xilinx PCIe高速接口入门实战(一)

引言&#xff1a;本文对Xilinx 7 Series Intergrated Block for PCI Express PCIe硬核IP进行简要介绍&#xff0c;主要包括7系列FPGA PCIe硬核资源支持、三IP硬核差异、PCIe硬核资源利用等相关内容。 1. 概述 1.1 7系列FPGA PCIe硬件资源支持 7系列FPGA对PCIe接口最大支持如…

【第三讲】Spring Boot 3.4.0 新特性详解:增强的配置属性支持

Spring Boot 3.4.0 版本在配置属性的支持上进行了显著增强&#xff0c;使得开发者能够更灵活地管理和使用应用程序的配置。新的特性包括对配置属性的改进、类型安全增强、以及对环境变量的更好支持。这些改进旨在提升开发效率和代码可读性&#xff0c;同时简化配置过程。本文将…

如何使用 Chrome 无痕浏览模式访问网站?

无痕浏览&#xff08;Incognito Mode&#xff09;是 Google Chrome 浏览器提供的一种隐私保护功能&#xff0c;它允许用户在一个独立的会话中浏览网页&#xff0c;而不会记录用户的浏览历史、下载历史、表单数据等。这对于希望保护个人隐私或进行临时性匿名浏览的用户来说非常有…

拥抱 OpenTelemetry:阿里云 Java Agent 演进实践

作者&#xff1a;陈承 背景 在 2018 年的 2 月&#xff0c;ARMS Java Agent 的第一个版本正式发布&#xff0c;为用户提供无侵入的的可观测数据采集服务。6 年后的今天&#xff0c;随着软件技术的迅猛发展、业务场景的逐渐丰富、用户规模的快速增长&#xff0c;我们逐渐发现过…

AI数据分析工具(二)

豆包-免费 优点 强大的数据处理能力&#xff1a; 豆包能够与Excel无缝集成&#xff0c;支持多种数据类型的导入&#xff0c;包括文本、数字、日期等&#xff0c;使得数据整理和分析变得更加便捷。豆包提供了丰富的数据处理功能&#xff0c;如数据去重、填充缺失值、转换格式等…

C/C++ 数据结构与算法 【时间复杂度和空间复杂度】【日常学习,考研必备】

一、时间复杂度 定义&#xff1a;时间复杂度描述了算法运行时间随输入大小增长而增长的趋势。它主要关注的是算法中最耗时的部分&#xff0c;并忽略常数因子、低阶项等细节。表示方法&#xff1a;通常使用大O符号&#xff08;Big O notation&#xff09;来表示时间复杂度。例如…

linux 文件权限,修改权限,c库调用

参考chmod 777 到底是啥 ???看完这个你就完全懂了&#xff01;-CSDN博客 ls -l 查看当前目录文件的权限 会有一个十位的东西 分别为 d:这是一个文件夹 后面3*3位分别表示所有者用户&#xff0c;同组用户&#xff0c;其他用户的读(r)&#xff0c;写(w)&#xff0c;执行(x)…

mysql 事务之LBCC与MVCC

一、事务 数据库事务&#xff08;Database Transaction&#xff09;是数据库管理系统&#xff08;DBMS&#xff09;中执行的一系列操作&#xff0c;这些操作被当作一个逻辑单元进行处理&#xff0c;以保证数据的一致性和完整性。 ACID&#xff0c;事务四个关键特性 1、原子性…

Wireshark 4.4.2:安全更新、错误修复、更新协议支持

流行的网络协议分析器Wireshark已更新至4.4.2版本。它可用于网络故障排除、分析、开发和教育。 已修复以下漏洞&#xff1a; wnpa-sec-2024-14 FiveCo RAP 解剖器无限循环。wnpa-sec-2024-15 ECMP 解析器崩溃。 更新的协议支持&#xff1a; ARTNET、ASN.1 PER、BACapp、B…

Vue-01

Vue框架 Vue官网&#xff1a; Vue.js 框架 数据模型和view的通信就是依靠viewmodel的关键。 目前主流版本仍然是vue2版本。 Vue快速入门 1.新建一个HTML文件&#xff0c;引入Vue.js文件。Vue.js文件是官方引入的一个文件&#xff0c;我们如果要使用Vue就必须引入这个文件。…