javascript中原型链(__proto__)与原型(prototype)
JavaScript中原型链(proto)与原型(prototype)
在JavaScript中,理解原型链(__proto__
)和原型(prototype
)对于深入掌握面向对象编程至关重要。本文将通过示例代码,详细解析__proto__
和prototype
之间的关系,以及它们在对象和构造函数之间的作用。
一、基本概念
1. 构造函数与实例对象
- 构造函数:在JavaScript中,函数可以作为构造函数使用,通过
new
关键字创建实例对象。 - 实例对象:由构造函数创建的对象,继承了构造函数的属性和方法。
2. 原型(prototype
)
- prototype:每个函数(包括构造函数)都有一个
prototype
属性,指向一个对象,这个对象被称为原型对象。 - 原型对象:存储共享的属性和方法,供所有实例对象访问。
3. 原型链(__proto__
)
- proto:每个对象都有一个
__proto__
属性,指向创建该对象的构造函数的原型对象。 - 原型链:通过
__proto__
属性,将对象、构造函数和原型对象连接起来,形成一个链式结构。
二、示例代码解析
下面通过一段示例代码,逐步解析__proto__
和prototype
之间的关系。
function Person(name, age){this.name = name;this.age = age;
}const person = new Person('Tom', 18);// 构造函数的prototype就是实例对象的__proto__
console.log(Person.prototype === person.__proto__); // true// 实例对象的constructor指向构造函数
console.log(person.constructor === Person); // true// 实例对象的__proto__对象上的constructor指向的又是Person构造函数
console.log(person.__proto__.constructor === Person); // true// 实例对象的__proto__对象的__proto__指向的是Object构造函数的prototype
console.log(person.__proto__.__proto__ === Object.prototype); // true// 每一个构造函数也是一个对象,所以也都有__proto__属性,指向的是Function构造函数的prototype
console.log(Person.__proto__ === Function.prototype); // true// Function构造函数的prototype的constructor指向Function构造函数
console.log(Function.prototype.constructor === Function); // true// Function的prototype的__proto__指向Object的prototype
console.log(Function.prototype.__proto__ === Object.prototype); // true// 因为所有构造函数的__proto__都是指向Function的prototype,所以Function构造函数的prototype和__proto__是相等的
console.log(Function.__proto__ === Function.prototype); // true
1. 实例对象与构造函数的关系
console.log(Person.prototype === person.__proto__); // true
- 解析:
Person.prototype
是构造函数Person
的原型对象。person.__proto__
是实例对象person
的原型,指向Person.prototype
。- 因此,
Person.prototype === person.__proto__
返回true
。
2. 实例对象的constructor属性
console.log(person.constructor === Person); // true
- 解析:
- 实例对象
person
的constructor
属性指向其构造函数Person
。 - 因此,
person.constructor === Person
返回true
。
- 实例对象
3. 原型对象的constructor属性
console.log(person.__proto__.constructor === Person); // true
- 解析:
person.__proto__
是Person.prototype
,它有一个constructor
属性,指向构造函数Person
。- 因此,
person.__proto__.constructor === Person
返回true
。
4. 原型链向上查找
console.log(person.__proto__.__proto__ === Object.prototype); // true
- 解析:
person.__proto__
是Person.prototype
。Person.prototype.__proto__
指向Object.prototype
。- 因此,
person.__proto__.__proto__ === Object.prototype
返回true
。
5. 构造函数也是对象
console.log(Person.__proto__ === Function.prototype); // true
- 解析:
- 构造函数
Person
本身是一个函数对象,所以它的__proto__
属性指向Function.prototype
。 - 因此,
Person.__proto__ === Function.prototype
返回true
。
- 构造函数
6. Function构造函数的关系
console.log(Function.prototype.constructor === Function); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true
console.log(Function.__proto__ === Function.prototype); // true
- 解析:
Function.prototype
是Function
构造函数的原型对象。Function.prototype.constructor
指向Function
自身。Function.prototype.__proto__
指向Object.prototype
,因为函数也是对象。Function.__proto__
指向Function.prototype
,因为Function
也是函数,是自己的构造函数。- 因此,上述三个
console.log
均返回true
。
三、原型链查找属性的过程
console.log(person.__proto__); // Person {}
console.log(person.__proto__.__proto__); // Object {}
console.log(person.__proto__.__proto__.__proto__); // null
- 解析:
person.__proto__
是Person.prototype
。person.__proto__.__proto__
是Object.prototype
。person.__proto__.__proto__.__proto__
为null
,表示原型链的顶端。
四、总结
1. 关于__proto__
和prototype
-
__proto__
:- 是每个对象都有的内置属性,指向其构造函数的原型对象。
- 用于实现对象的原型链,在查找属性时,如果对象自身没有,会沿着
__proto__
向上查找。
-
prototype
:- 是构造函数的属性,指向原型对象。
- 原型对象上定义的方法和属性会被构造函数的所有实例共享。
2. 关于构造函数和实例对象
-
实例对象的
__proto__
:- 指向构造函数的
prototype
属性。
- 指向构造函数的
-
实例对象的
constructor
:- 通过
__proto__
找到原型对象,原型对象的constructor
指向构造函数。
- 通过
-
构造函数的
__proto__
:- 因为构造函数本身是一个函数对象,所以它的
__proto__
指向Function.prototype
。
- 因为构造函数本身是一个函数对象,所以它的
3. 关于原型链的查找过程
- 当访问对象的属性时,JavaScript引擎会先查找对象自身的属性。
- 如果找不到,会沿着
__proto__
属性指向的原型对象继续查找。 - 这个过程会一直持续,直到找到属性或到达原型链的顶端(
null
)。
4. 关于Function和Object
-
Function构造函数:
- 是所有函数的构造函数,包括
Function
自身。 Function.__proto__ === Function.prototype
,因为Function
是一个函数,其__proto__
指向Function.prototype
。
- 是所有函数的构造函数,包括
-
Object构造函数:
- 是所有对象的构造函数,包括
Function.prototype
。 Function.prototype.__proto__ === Object.prototype
。
- 是所有对象的构造函数,包括
五、深入思考
-
为什么
Function.__proto__ === Function.prototype
?- 因为
Function
是所有函数的构造函数,包括它自己。Function
作为一个函数对象,其__proto__
指向Function.prototype
。
- 因为
-
为什么
Object.__proto__ === Function.prototype
?Object
是一个函数(构造函数),所以其__proto__
指向Function.prototype
。
-
为什么
Function.prototype.__proto__ === Object.prototype
?Function.prototype
是一个对象,因此其__proto__
指向Object.prototype
。
相关文章:

javascript中原型链(__proto__)与原型(prototype)
JavaScript中原型链(proto)与原型(prototype) 在JavaScript中,理解原型链(__proto__)和原型(prototype)对于深入掌握面向对象编程至关重要。本文将通过示例代码,详细解析__proto__和prototype之间的关系&a…...

基于多种机器学习的酒店客户流失预测模型的研究与实现
文章目录 有需要本项目的代码或文档以及全部资源,或者部署调试可以私信博主项目介绍实现过程 有需要本项目的代码或文档以及全部资源,或者部署调试可以私信博主 项目介绍 项目背景: 在当今竞争激烈的酒店行业中,预测和防止客户流…...

Unity实现自定义图集(三)
以下内容是根据Unity 2020.1.0f1版本进行编写的 1、实现编辑器模式下进游戏前Pack全部自定义图集 同Unity的图集一样,Unity的编辑器模式会在进游戏前把全部的SpriteAtlas都打一次图集,如图: 我们也实现这样的效果。 首先需要获取全部的图集路径。因为目前使用的是以.…...

【测开面试真题】
针对地图导航设计测试用例 文章目录 1. selenium 定位元素的方式有几种?2. 自动化测试能够取代人工测试吗?3. 什么是回归测试? 1. selenium 定位元素的方式有几种? 🐧①通过CSS选择器定位;🐧②…...

RelationGraph实现工单进度图——js技能提升
直接上图: 从上图中可以看到整个工单的进度是从【开始】指向【PCB判责】【完善客诉】【PCBA列表】,同时【完善客诉】又可以同时指向【PCB判责】【PCBA列表】,后续各自指向自己的进度。 直接上代码: 1.安装 1.1 Npm 方式 npm …...

针对脚本爬虫攻击的防御策略与实现
随着互联网的发展,网站和应用程序面临着越来越多的自动化攻击,其中包括使用脚本进行的大规模数据抓取,即所谓的“爬虫攻击”。这类攻击不仅影响网站性能,还可能导致敏感数据泄露。本文将探讨如何识别爬虫攻击,并提供一…...

JVM发展历程
JVM发展历程 Sun Classic VM 早在1996年Java1.0版本的时候,Sun公司发布了一款名为sun classic VM的Java虚拟机,它同时也是世界上第一款商用Java虚拟机,JDK1.4时完全被淘汰。这款虚拟机内部只提供解释器。现在还有及时编译器,因此…...

C语言 | Leetcode C语言题解之第470题用Rand7()实现Rand10()
题目: 题解: // The rand7() API is already defined for you. // int rand7(); // return a random integer in the range 1 to 7int rand10() {while(true) {int index (rand7() - 1) * 7 rand7(); if(index < 40) return index % 10 1; } }...

【JavaScript】拷贝对象的几种方式与对比
#工作中拷贝对象是常有的事,我们需要分清楚深浅拷贝,一般来说要做的都是深拷贝,不然会有关联影响# 解构赋值 es6新语法,简洁是简洁,但是需要注意深拷贝只针对第一层 使用方式:{...obj} let stu {name:…...

高防服务器为何有时难以防御CC攻击及其对策
高防服务器通常被用来抵御各种类型的DDoS攻击,包括CC(Challenge Collapsar)攻击。然而,在某些情况下,即使是配备了高级防护措施的高防服务器也可能难以完全防御CC攻击。本文将探讨导致这一现象的原因,并提供…...

性能测试工具locust —— Python脚本参数化!
1.1.登录用户参数化 在测试过程中,经常会涉及到需要用不同的用户登录操作,可以采用队列的方式,对登录的用户进行参数化。如果数据要保证不重复,则取完不再放回;如可以重复,则取出后再返回队列。 def lo…...

Java中的拦截器、过滤器及监听器
过滤器(Filter)监听器(Listener)拦截器(Interceptor)关注点web请求系统级别参数、对象Action(部分web请求)如何实现函数回调事件Java反射机制(动态代理)应用场…...

Nginx 和 Lua 设计黑白名单
使用 Nginx 和 Lua 设计黑白名单机制,借助 Redis 存储 在现代网络应用中,安全性是一个不可忽视的关键因素。应用程序需要能够有效地管理访问权限,以保护其资源不被恶意用户攻击。黑白名单机制是实现访问控制的一种有效方式。本文将详细介绍如…...

【部署篇】Redis-01介绍
一、Redis介绍 1、什么是Redis? Redis,英文全称是Remote Dictionary Server(远程字典服务),Redis是一个开源的、使用ANSI C语言编写的Key-Value存储系统,支持网络、可基于内存亦可持久化。 它提…...

R语言的Meta分析【全流程、不确定性分析】方法与Meta机器学习技术应用
Meta分析是针对某一科研问题,根据明确的搜索策略、选择筛选文献标准、采用严格的评价方法,对来源不同的研究成果进行收集、合并及定量统计分析的方法,最早出现于“循证医学”,现已广泛应用于农林生态,资源环境等方面。…...

【text2sql】ReFSQL检索生成框架
论文标题为《ReFSQL: A Retrieval-Augmentation Framework for Text-to-SQL Generation》,发表在 EMNLP 2023 上。ReFSQL框架通过结构增强检索器来获取与当前问题语义和模式结构相似的样本,然后通过对比学习机制来引导模型学习到这些样本的特定知识&…...

美国市场跨平台应用程序本地化流程的特点
为美国市场本地化移动应用程序是为了创造一种自然、直观、与多元化和精通技术的受众文化相关的体验。美国是世界上最大、最具竞争力的应用程序市场之一,用户期望高质量的性能以及在个人层面引起共鸣的内容。这个市场的本地化需要对美国语言、文化和行为有细致入微的…...

STM32 实现 TCP 服务器与多个设备通信
目录 一、引言 二、硬件准备 三、软件准备 四、LWIP 协议栈的配置与初始化 五、创建 TCP 服务器 1.创建 TCP 控制块 2.绑定端口 3. 进入监听状态 4.设置接收回调函数 六、处理多个客户端连接 七、数据处理与通信管理 八、错误处理与资源管理 九、总结 一、引…...

EdgeNAT: 高效边缘检测的 Transformer
EdgeNAT: Transformer for Efficient Edge Detection 介绍了一种名为EdgeNAT的基于Transformer的边缘检测方法。 1. 背景与动机 EdgeNAT预测结果示例。(a, b):来自BSDS500的数据集的输入图像。(c, d):对应的真实标签。(e, f):由EdgeNAT检测到的边缘。(e)显示了由于颜色变化…...

Github优质项目推荐 - 第六期
文章目录 Github优质项目推荐 - 第六期一、【WiFiAnalyzer】,3.4k stars - WiFi 网络分析工具二、【penpot】,33k stars - UI 设计与原型制作平台三、【Inpaint-Anything】,6.4k stars - 修复图像、视频和3D 场景中的任何内容四、【Malware-P…...

力扣21~30题
21题(简单): 分析: 按要求照做就好了,这种链表基本操作适合用c写,python用起来真的很奇怪 python代码: # Definition for singly-linked list. # class ListNode: # def __init__(self, v…...

AGI|如何构建一个RAG应用?入门新手攻略!
目录 一、概述 二、过程概述 三、如何优化提问? 四、路由和高级查询 五、丰富索引结构 六、重排序上下文 七、总结 一、概述 Retrieval Augmented Generation RAG 检索增强的内容生成。 从字面上来看检索只是一种手段途径,在人工智能领域中存在多种…...

【.NET 8 实战--孢子记账--从单体到微服务】--角色(增加/删除/修改/查询)
本节我们将开始编写角色相关的接口 一、需求 本节的要做的需求如下: 编号需求标题需求内容1增加角色角色名称不能重复2删除角色角色逻辑删除3修改角色修改的名称不能和已有名称重复4查询角色不分页查询,根据角色名模糊匹配 二、Role类和Role表 这一…...

数据结构-栈与队列笔记
普通的双端队列 用栈实现队列 232. 用栈实现队列 - 力扣(LeetCode) import java.util.ArrayDeque; import java.util.Deque;class MyQueue {// 使用双端队列(Deque)来实现一个队列Deque<Integer> input; // 用于存放新加…...

DevExpress WPF中文教程:如何解决数据更新的常见问题?
DevExpress WPF拥有120个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…...

SpringBoot基础(四):bean的多种加载方式
SpringBoot基础系列文章 SpringBoot基础(一):快速入门 SpringBoot基础(二):配置文件详解 SpringBoot基础(三):Logback日志 SpringBoot基础(四):bean的多种加载方式 目录 一、xml配置文件二、注解定义bean1、使用AnnotationCon…...

JavaScript网页设计案例:构建动态交互的在线图书管理系统
JavaScript网页设计案例:构建动态交互的在线图书管理系统 在当今的数字化时代,网页设计不仅仅是关于美观和布局,更重要的是用户体验和互动性。JavaScript,作为一种强大的编程语言,在网页开发中扮演着至关重要的角色&a…...

嵌入式数据结构中线性表的具体实现
大家好,今天主要给大家分享一下,如何使用数据结构中的线性表以及具体的实现。 第一:线性表的定义和表示方法 线性表的定义 – 线性表就是零个或多个相同数据元素的有限序列。 • 线性表的表示方法 – 线性表记为: L=(a0,∙∙∙∙∙∙∙∙ai-1aiai+1 ∙∙∙∙∙∙an-1) •…...

Redis高级篇 —— 分布式缓存
Redis高级篇 —— 分布式缓存 文章目录 Redis高级篇 —— 分布式缓存1 Redis持久化1.1 RDB1.2 RDB的fork原理1.3 RDB总结1.4 AOF持久化1.5 RDB和AOF的对比 2 Redis主从2.1 搭建主从架构2.2 数据同步原理2.2.1 全量同步2.2.2 增量同步 3 Redis哨兵3.1 哨兵的作用和原理3.1.1 哨兵…...

彩族相机内存卡恢复多种攻略:告别数据丢失
在数字时代,相机内存卡作为我们存储珍贵照片和视频的重要媒介,其数据安全性显得尤为重要。然而,意外删除、错误格式化、存储卡损坏等情况时有发生,导致数据丢失,给用户带来不小的困扰。本文将详细介绍彩族相机内存卡数…...