【JS】JavaScript 中的原型与原型链

JavaScript 中的原型与原型链

      • 原型
        • 1 函数中 prototype 指向原型对象
        • 2 对象中 __proto__ 指向原型对象
        • 3 原型对象中 constructor 指向构造函数
        • 4 __proto__ 与 [[Prototype]] 的关系
        • 5 所有非空类型数据,都具有原型对象
        • 6 new运算符做了哪些事情
      • 原型链
        • 1 举个栗子
          • 1.1 直接创建一个对象
          • 1.2 数字、字符串、数组等类型数据, 下面以数字为例, 其他类型大同小异
          • 1.3 一个复杂的例子
        • 2 原型链的作用

原型

1 函数中 prototype 指向原型对象

当我们创建一个函数时,函数都会有一个默认属性 prototype

该属性指向一个对象, 该对象就被称之为 原型对象

function fun(){

}
fun.prototype // 原型对象

在这里插入图片描述

2 对象中 proto 指向原型对象

当函数作为 普通函数 进行调用时,该属性不会有任何作用

当函数被作为 构造函数 进行调用 (使用 new 运算符调用) 时,构建出来的 实例对象 会有一个属性 __proto__ 指向 原型对象

function fun(name){
  this.name = name
}

fun.prototype // 原型对象

// 函数被作为构造函数进行调用
const obj = new fun('swim') 

// 实例对象.__proto__ 指向 构造函数.prototype
obj.__proto__ === fun.prototype // true

》》》2

3 原型对象中 constructor 指向构造函数

原型对象 默认会有一个特殊的属性 constructor, 该属性又指向了函数本身

function fun(name){
  this.name = name
}

fun.prototype // 原型对象

// 原型对象中 constructor 指向构造函数
fun.prototype.constructor === fun // true

在这里插入图片描述

4 proto 与 [[Prototype]] 的关系

如果将 实例对象 打印出来, 会发现对象中并不具有 __proto__ 属性,恰恰相反有个特殊的 [[Prototype]] 属性。

《《《《4

__proto__ 并不是 ECMAScript 语法规范的标准, 它只是大部分浏览器厂商实现或说是支持的一个属性, 通过该属性方便我们访问、修改原型对象

遵循 ECMAScript 标准, [[Prototype]] 才是正统, [[Prototype]] 无法被直接修改、引用

ECMAScript 6 开始, 可通过 Object.getPrototypeOf()Object.setPrototypeOf() 来访问、修改 原型对象

简单理解: __proto__[[Prototype]] 是同一个东西, __proto__ 是非标准的, [[Prototype]] 才是标准的, 但是它们都是指向 原型对象

那么问题来了, 我们访问的 __proto__ 在哪里呢? 实际上它是被添加在 Object.prototype 上, 然后通过 原型链(后面会详细展开说明) 我们就能够访问到该属性

5 所有非空类型数据,都具有原型对象

任何非空数据,本质上都是通过对应的构造函数构建出来的,所以他们都具有 __proto__ 属性,指向构造函数的原型对象。

如果需要判断某个值的原型对象,只需要确认该值是通过哪个构造函数构建的即可,只要确认了构造函数,那么该值的 __proto__ 必然指向该构造函数的原型对象 prototype

// 数字
const num = 1
// 数字是通过 Number 构建的, 那么其原型对象等于 Number.prototype
num.__proto__ === Number.prototype // true

// 字符串
const str = 'str'
// 字符串是通过 String 构建的, 那么其原型对象等于 String.prototype
str.__proto__ === String.prototype // true

// 布尔类型
const bool = false
// 布尔值是通过 Boolean 构建的, 那么其原型对象等于 Boolean.prototype
bool.__proto__ === Boolean.prototype // true

// Symbol
const sym = Symbol('symbol')
// sym 是通过 Symbol 构建的, 那么其原型对象等于 Symbol.prototype
sym.__proto__ === Symbol.prototype // true

// BigInt
const big = BigInt(1)
// big 是通过 BigInt 构建的, 那么其原型对象等于 BigInt.prototype
big.__proto__ === BigInt.prototype // true

// 对象
const obj = { age: 18 }
// 对象是通过 Object 构建的, 那么其原型对象等于 Object.prototype
obj.__proto__ === Object.prototype // true

// 函数
const fun = () => {}
// 函数是通过 Function 构建的, 那么其原型对象等于 Function.prototype
fun.__proto__ === Function.prototype // true

// 数组
const arr = [1, 2, 3]
// 数组是通过 Array 构建的, 那么其原型对象等于 Array.prototype
arr.__proto__ === Array.prototype // true

6 new运算符做了哪些事情
  1. 创建一个新的空对象 A
  2. 往空对象挂载 构造函数 Com原型对象: 对象 A 创建 __proto__ 属性, 并将 构造函数prototype 属性赋值给 __proto__
  3. 执行 构造函数 Com: 改变 构造函数 this 指向, 指向空对象 A, 并执行 构造函数, 往空对象注入属性
  4. 判断 构造函数 是否返回一个对象?
  • 是: 如果 构造函数 也返回了一个对象 B, 则最终 new 出来的对象则为返回的对象 B
  • 否: 最终 new 出来的对象为最初创建的对象 A
因此当我们执行
var o = new Foo();

实际上执行的是:
// 1. 创建一个新的空对象 A
let A = {};

// 2. 往空对象挂载, 挂载构造函数 Com 的原型对象: obj.__proto__ === Com.prototype;
Object.setPrototypeOf(A, Com.prototype);

// 3. 执行构造函数: 改变构造函数 this 指向, 指向对象 A, 往 A 注入属性
let B = Com.apply(A, args);

// 4. 判断构造函数是否返回对象: 是则取返回值、否则取最初创建的对象 A
const newObj = B instanceof Object ? res : A;

原型链

原型链是一种对象之间的链接机制,它用于实现对象之间的继承和属性访问。

每个JavaScript对象都有一个原型(prototype),原型是一个对象或null。当你访问一个对象的属性时,如果该对象自身没有该属性,JavaScript 引擎会沿着原型链向上查找,直到找到具有该属性的对象或到达原型链的末尾(即null)。这样,对象可以继承其原型的属性和方法。

根据上文,所有非空数据,都可以通过 __proto__ 指向原型对象,如果原型对象非空,那么必然会有 __proto__ 指向自己的原型对象,如此一层一层往上追溯,依此类推,就形成了一整条链路,一直到某个原型对象为null,才能达到最后一个链路的最后环节,而原型对象之间这种链路关系被称之为原型链 (prototype chain)

1 举个栗子
1.1 直接创建一个对象
const obj = { age: 18 };

从对象 obj 视角来看:
1. obj 本质上是通过 Object 构建出来的,那么 obj.__proto__ === Object.prototype
2. Object.prototype 的原型对象为 null,因此原型链到此结束

》》》图5

1.2 数字、字符串、数组等类型数据, 下面以数字为例, 其他类型大同小异
let num = 1;

1. num 本质上是通过 Number 构建出来的,那么 num.__proto__ === Number.prototype
2. Number.prototype 本质上是一个对象,是通过 Object 构建出来的,
	那么 Number.prototype.__proto__ === Object.prototype
3. Object.prototype 的原型对象为 null,因此原型链到此结束

num.__proto__ === Number.prototype // true
Number.prototype.__proto__ === Object.prototype // true
Object.prototype.__proto__  // null 原型链结束
1.3 一个复杂的例子
function Person(age) {
  this.age = age       
}
var person = new Person(100)

从对象  person 视角来看:
	1. person 是通过 Person 构建出来的, 那么 person.__proto__ 等于 Person.prototype
	2. Person.prototype 是个对象, 是通过 Object 构建出来了, 那么Person.prototype.__proto__ 等于 Object.prototype
	3. Object.prototype 的 原型对象 为 null, 原型链 到此结束

2 原型链的作用
  • 查找属性: 当我们试图访问 对象属性 时, 它会先在 当前对象 上进行搜寻, 搜寻没有结果时会继续搜寻该对象的 原型对象, 以及该对象的 原型对象原型对象, 依次层层向上搜索, 直到找到一个名字匹配的属性或到达原型链的末尾
function Person(age) {
  this.age = age
}

Person.prototype.name = 'klx'
Person.prototype.age = 18

const person = new Person(28)

person // 当前对象: { age: 28 }

person.name // klx, 取自原型对象 Person.prototype
person.age // 28, 取自当前对象

person.toString() // [object Object], 取自原型对象 Object.prototype

person.address // undefined, 沿着原型链找不到 address 

  • 继承属性和方法:原型链允许对象继承其原型的属性和方法。当你访问一个对象的属性时,如果对象本身没有该属性,它会通过原型链访问原型对象的属性。这样可以实现属性的共享和代码的重用。

  • 创建对象关联:通过原型链,你可以将一个对象与另一个对象关联起来,形成一个对象链。这样,一个对象可以通过原型链访问到另一个对象的属性和方法。

  • 实现对象的多态性:在原型链中,可以通过在原型对象上定义相同名称的属性或方法,从而实现对象的多态性。当对象在原型链中找到具有相同名称的属性或方法时,会使用最近的那个

JavaScript中的原型链是基于原型继承的概念,它允许对象通过原型链接到其他对象,并继承其属性和方法。这种机制在JavaScript中是一种重要的特性,使得对象之间可以实现继承和共享,提供了灵活性和代码复用的机制。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UI自动测试框架-selenium(1) selenium介绍和选择器

目录 1.selenium是什么 2.定位元素 2.1 css选择器 2.1.1 选择id 2.1.2 class 2.1.3使用标签选择 2.1.4父类选择器 子类选择器 2.2 xpath 1.selenium是什么 selenium是用来做web端自动化测试的框架,它支持各种游览器,各种平台,支持各种语言(如 Python,Java,C#,JS,Ruby..…

elementUI(Vue2)和elementPlus(Vue3)图标icon差异

Vue2用法 <i class"el-icon-edit"></i><el-button type"primary" icon"el-icon-search">搜索</el-button> Vue3用法 <!-- 使用 el-icon 为 SVG 图标提供属性 --> <template><div><el-icon :siz…

神经网络梯度下降优化参数

损失函数 神经网络的最终目的就是最小化损失函数的过程&#xff0c;损失函数越小&#xff0c;证明模型的预测值就越接近真实值。 梯度下降算法 为了最优化损失函数&#xff0c;开发了梯度下降算法&#xff0c;这里的梯度就是高等数学中的梯度。 误差反向传播算法 前向传播…

螺旋卫星通信天线设计与有限元分析matlab仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 卫星搭载用于通讯的螺旋型天线&#xff0c;卫星尺寸&#xff1a; 10cm*10cm*30cm&#xff1b;天线类型&#xff1a;螺旋&#xff1b;天线UHF&#xff08;约1GHz – 3GHz&#…

酷开科技OTT大屏营销重构新生,让营销被看见

在过去的十年间&#xff0c;中国视听新媒体产业迎来了发展的黄金时代。这一时期&#xff0c;见证了视听新媒体业态的广泛涌现&#xff0c;它们不仅迅速成长和扩张&#xff0c;而且逐步走向了成熟。互联网电视的兴起&#xff0c;为消费者带来了多样化的视听内容享受方式&#xf…

提升效率!商务电子邮件在WorkPlace中如何高效运用?安全保障!

高效和安全的沟通是任何组织成功的核心。在我们关于电子邮件类型的系列文章的第二期中&#xff0c;我们将重点关注商业电子邮件在促进无缝交互中的关键作用。当你身处重要的工作场环境时&#xff0c;本系列的每篇文章都提供了电子邮件的不同维度的视角。 “2024年&#xff0c;全…

ArcGIS Pro、R与INVEST:探索生态系统服务评估的深度与广度

生态系统服务是指生态系统所形成的用于维持人类赖以生存和发展的自然环境条件与效用&#xff0c;是人类直接或间接从生态系统中得到的各种惠益。联合国千年生态系统评估&#xff08;Millennium ecosystem assessment&#xff0c;MA&#xff09;提出生态系统服务包括供给、调节、…

广州5k前端面试题惊呆我!!!(内容太肝,谨慎入内)

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

R语言Meta分析核心技术:科研论文写作与数据可视化技巧

R语言作为一种强大的统计分析和绘图语言&#xff0c;在科研领域发挥着日益重要的作用。其中&#xff0c;Meta分析作为一种整合多个独立研究结果的统计方法&#xff0c;在R语言中得到了广泛的应用。通过R语言进行Meta分析&#xff0c;研究者能够更为准确、全面地评估某一研究问题…

C# xaml框架以及Java的ORM介绍

c#有ASP.Net,.NET以及EF Core这几个重要的运行时和框架.分别用于web,应用以及数据库的ORM. 目前跨平台的有Avalonia UI,.Net MAUI以及Uno Platform,至于WPF等本身不是跨平台的,但可以依靠其他库实现跨平台.这里面Avalonia应该是认为bug比较少的. 当然目前最火的跨平台解决方案…

Databend x CubeFS:面向未来的企业级云原生数据存储与分析

用场景的丰富&#xff0c;企业面临着前所未有的数据存储挑战。大规模数据存储变得日常化&#xff0c;伴随着超大容量和快速变化的I/O需求&#xff0c;传统的存储解决方案已经难以满足企业对弹性、运维效率及总体拥有成本&#xff08;TCO&#xff09;的更高要求。这些挑战促使基…

【数据库系统】SQL和T-SQL

第四章 SQL 基本内容 系统结构、DDL、DML、视图、数据控制、嵌入式SQL SQL介绍 特点 一体化&#xff1b;面向集合操作&#xff1b;非过程化语言&#xff1b;可以单独写&#xff0c;也可以作为嵌入式语言&#xff08;JDBC&#xff09; 体系结构 数据库存储结构 逻辑存储结构 面…

vue key的bug

今天遇到一个bug&#xff0c;列表删除元素时&#xff0c;明明在外层设置了key&#xff0c;但是列表元素的状态居然复用了&#xff0c;找了好久原因&#xff0c;最后是key的取值问题&#xff0c;记录一下。 首先key可以取undefine&#xff0c;这个是不会报错的 然后项目的代码结…

工商银行ECOS系统应用架构

2019 年 11 月 8 日&#xff0c;工商银行在北京正式发布 ECOS 智慧银行生态系统。ECOS 以 Ecosystem&#xff08;生态系统&#xff09;前四个字母命名。其中E 代表“企业级”&#xff08;Enterprise-level&#xff09;&#xff0c;C 代表“以客户为中心”&#xff08;Customer-…

rpc详解rpc框架

文章目录 概述rpc的优点组件工作流程&RPC的底层原理RPC的底层原理 RPC框架rpc框架优点RPC 的实现基础RPC的应用场景RPC使用了哪些关键技术rpc 调用异常一般怎么处理rpc和http的区别为什么RPC要比HTTP更快一些Dubbo和openfeign 区别远程调用RPC框架传输协议传输速度 概述 在…

6.shell case控制语句

case控制语句 1.什么是case case条件语句相当于多分支的if/elif/else条件语句&#xff0c;主要还是用来做条件判断的,常被应用于实现系统服务启动脚本。 case语句中&#xff0c;会将case获取的变量值与表达式部分的值1、值2、值3等逐个进行比较&#xff0c;如果变量值和某个表…

vue3 报错 require is not defined

问题 require is not defined 原因 vite 不支持require的用法&#xff0c; webpack是支持的 解决 方法一&#xff1a; 更改vite使用语法 vite官网 方法二 安装转换插件vite-plugin-require-transform 仓库地址 参考 关于Vite不能使用require问题 方法二Vite 踩坑 —— …

html5cssjs代码 036 CSS默认值

html5&css&js代码 036 CSS默认值 一、代码二、解释 CSS默认值&#xff08;也称为浏览器默认样式&#xff09;是指当HTML元素没有应用任何外部CSS样式时&#xff0c;浏览器自动为这些元素赋予的一组基本样式。这些样式是由浏览器的默认样式表&#xff08;User Agent sty…

【Godot4.2】实现鼠标控制对象(控件)旋转

概述 在一些情况下我们可能需要使用鼠标控制对一个图形或对象&#xff08;如控件&#xff09;进行旋转。 通过如下图的分析&#xff1a; 我们可以知道&#xff1a; 我们只需要求出对象&#xff08;如控件&#xff09;中心点C到鼠标点击的位置start的向量与中心点C到鼠标移动…

STM32最小核心板使用HAL库实现CAN接口通讯(轮询方式)

这里使用了CAN1的接口&#xff0c;具体使用MX创建项目就不放了 需要注意的是&#xff0c;由于是最小核心没有CAN的收发模块需要外接一个 STM32核心板接CAN收发模块不需要交叉 /**CAN GPIO ConfigurationPA11 ------> CAN_RXPA12 ------> CAN_TX */ CAN收发模块…