JavaScript Reference Type解读

news2024/9/9 7:42:45

Reference Type

在 JavaScript 中,引用类型(Reference Type)是一种数据存储和操作的方式。

Reference Type 是 ECMA 中的一个“规范类型”。我们不能直接使用它,但它被用在 JavaScript 语言内部。

Reference Type 的值是一个三个值的组合 (base, propertyname, strict)

  • base 是对象。
    在 JavaScript 中,所有对象或者函数都有所属对象。在全局上下文中,base 等同于全局对象(global);在函数的执行上下文中,base 等同于变量对象(vo)或活动对象(ao);而在处理对象属性时,base 等同于所属的对象(owerObject)。
  • propertyname 是属性名。
  • strictuse strict 模式下为 true

用伪代码表示:

var valueOfReferenceType = {
  base: // 对象的所属对象
  propertyname: // 属性名
};

示例:

let obj1 = { name: 'Alice' };
console.log(obj1.name); // Alice

当访问 obj1.name 时,得到的引用类型的值中,base 就是 obj1 对象本身,propertyname 就是属性name

引用类型本身并不保存真正的值,而是存储对数据实际存储位置的引用(类似于指针)。这意味着多个变量可以引用同一个对象,对其中一个变量所做的修改会反映在其他引用该对象的变量上。
常见的引用类型包括对象(Object)、数组(Array)和函数(Function)、日期(Date)、正则表达式(RegExp)。

以Object为例,解读Reference Type

在 JavaScript 中,对象(Object)是一种引用类型(Reference Type)。

当我们在读取对象的某个属性的时候,'.'返回的准确来说不是属性的值,而是一个特殊的Reference Type类型的值,在这个其中存着属性的值和它的来源对象。

示例:

let obj1 = { name: 'Alice' };
let obj2 = obj1;  // obj2 复制了 obj1 的引用

console.log(obj1.name ===  obj2.name); // true

function updateObj(obj) {
	obj.age = 30
	obj.name = 'Bob'
}
updateObj(obj2);
console.log(obj2); // { name: 'Bob', age: 30 }
console.log(obj1.name, obj1.age); // 'Bob', 30   因为 obj1 和 obj2 指向同一个对象
console.log(obj1.name ===  obj2.name); // true

在示例中,let obj1 = { name: 'Alice' };做了2件事:

  1. 在内存的堆中创建了一个对象,这个对象具有一个名为 name 的属性,其值为 "Alice"
  2. 然后,在栈中创建了变量 obj1obj1存储的是指向堆中的对象{ name: 'Alice' }的引用(而不是对象本身的值)。

let obj2 = obj1;obj1 的引用赋值给了 obj2 。因此,obj1obj2 保存的都是对同一个对象的引用。
当调用 updateObj(obj2) 函数时,虽然传递的是 obj2 ,但由于是引用传递,实际上传递的是指向堆中对象的引用。在函数内部对这个对象进行修改,会同时反映在 obj1obj2 上。

打个比方,对象{ name: 'Alice' }就像是家里大门的锁,一家几口人都各有1把钥匙能开门回家。使用钥匙obj1的人开门回家,并做好了饭。使用钥匙obj2开门回家的人,就可以直接恰饭了。

以函数为例,解读Reference Type

obj.method() 语句中有两个操作:

  1. 首先,点 '.' 取了属性 obj.method 的值。
  2. 接着 () 执行了它。

在通过点 '.' 操作符或方括号[]操作符调用方法时,this的指向与引用类型的对象有关。
在一些复杂的表达式中,可能会导致this丢失或指向不正确。

示例:

let user = {
  name: "Alice",
  hi() { console.log(this.name); },
  bye() { console.log("Bye"); }
};

user.hi(); // 正常运行,在hi()方法内部,this 正确地指向了 user 对象

// 现在让我们基于 name 来选择调用 user.hi 或 user.bye
(user.name == "Alice" ? user.hi : user.bye)(); // Error! 
//Uncaught TypeError: Cannot read properties of undefined (reading 'name')

在示例中,根据三元运算(user.name == "John" ? user.hi : user.bye)判断具体使用哪个方法,结果是使用user.hi。接着该方法被通过 () 立刻调用。
执行user.hi报错Uncaught TypeError: Cannot read properties of undefined (reading 'name')

为什么会报错?

在 JavaScript 中,条件表达式返回的是函数本身,而不是函数的调用结果。

因此,在严格模式下:

  • 执行user.hi()语句,对属性 user.hi 访问的结果不是一个函数,而是一个 Reference Type 的值。当 () 被在 Reference Type 上调用时,它们会接收到关于对象和对象的方法的完整信息,然后可以设置正确的 this(在此处 = user)。
// user.hi() Reference Type 的值
(user, "hi", true)

其中,user 是对象本身,"hi" 是属性名,true 表示处于严格模式。

  • 当执行 hi = user.hi 后,hi 仅仅是函数本身,即hi() { console.log(this.name); }。它丢失了原有的 Reference Type 信息,也就丢失了与特定对象user的关联以及严格模式的相关设置。
    在严格模式下,如果直接调用变量函数 hithis的值会是undefined

(user.name == "Alice" ? user.hi : user.bye)();的详细写法如下:

// 把获取方法和调用方法拆成2个步骤
let func;
if(user.name == "Alice") {
  func = user.hi; // 把函数 user.hi 赋值给了变量 func
}ele{
  func = user.bye; // 把函数 user.bye 赋值给了变量 func
}
func(); // Uncaught TypeError: Cannot read properties of undefined (reading 'name')

当执行 func() 时,this 的指向不是 user 对象,thisundefined,导致无法正确访问 name 属性,引发错误。

解决方案:可以使用call、apply或bind方法来明确指定this的指向。

let func = (user.name == "Alice"? user.hi : user.bye);
func.call(user); 
// 通过 call 方法将 user 对象作为 this 传递给函数

Reference Type 是一个特殊的“中间人”内部类型,目的是从 '.' 传递信息给 () 调用。

总结

Reference Type 是语言内部的一个类型。

引用类型具有以下特点:

  • 存储方式
    引用类型的值在内存中的存储分为两部分,一部分是对象本身,存储在堆(heap)中;另一部分是对象的引用地址,存储在栈(stack)中。变量实际上存储的是这个引用地址。
    赋值了对象的变量存储的不是对象本身,而是该对象“在内存中的地址”。换句话说就是对该对象的“引用”。
  • 引用共享
    对象是“通过引用”存储和复制的。
  • 传递方式
    在函数传参时,引用类型是按引用传递。这意味着函数内部对参数的修改会影响到原始的对象或数组。
  • 可变性
    引用类型的值是可变的。例如,可以修改对象的属性或数组的元素。
  • 比较方式
    对于严格相等(===),比较的是引用地址是否相等,即是否是同一个对象;对于宽松相等(==),会进行类型转换后再比较值。
  • this 指向:在通过点'.'操作符或方括号[]操作符调用方法时,this的指向与引用类型的对象有关。在一些复杂的表达式中,可能会导致this丢失或指向不正确。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TiDB Hackathon 2024丨用 TiDB 构建未来的 AI 创新应用, 瓜分超 ¥210,000 奖金池!

2024 TiDB Future App Hackathon 来啦!这是第八届 TiDB Hackathon,TiDB Hackathon 自举办以来,已累计参赛人数超过 3000 人 !回顾去年的 TiDB Hackathon 赛事,有来自 88 个国家近 1500 名小伙伴参加,提交了…

IDEA某个项目被同事提交的代码导致不能进入Debug了,不是IDEA的问题。千万要避坑!

刚开始我发现突然不能进入debug了,打上去后就立马边灰了,我以为是我IDEA的问题,后来我换了其他项目都能正常进入debug. 而且后续,这个项目的其他同事也都不能进入debug了。 我就怀疑是项目中有人提交了代码导致的。 后来查…

必备插件自取 vue3.0 在vscode提升编码效率

一些vue开发中用到的插件,抽空总结一下,一是方便自己查看,另外是供其他需要的同学参考。在开发vue项目中,无论用什么编辑器一些好用的插件对我们来讲或许是必要的,因为好的插件既能方便我们编码,又能提升开…

文件解析漏洞--IIS--Vulhub

文件解析漏洞 一、IIS解析漏洞 用windowserver2003安装IIS测试 1.1 IIS6.X 方法一:目录解析 在网站下建立文件夹的名字为.asp/.asa的文件夹,其目录内的任何扩展名的文件都被IIS当作asp文件来解析并执行。 1.txt文件里是asp文件的语法查看当前时间 方…

PSO求解函数最小值的MATLAB例程|MATLAB源代码

本篇文章适合PSO入门,进阶的可能会觉得太简单的。 目录 PSO例程作用运行结果代码函数解释 例程修改tips PSO Particle Swarm Optimization,粒子群优化算法,通过模拟鸟群或鱼群的行为来寻找最优解。在计算时通过对一群粒子的位置和速度进行迭…

Stable Diffusion Windows本地部署超详细教程(手动+自动+整合包三种方式)

2022年作为AIGC(Artificial Intelligence Generated Content)时代的元年,各个领域的AIGC技术都有一个迅猛的发展,给工业界、学术界、投资界甚至竞赛界都注入了新的“AI活力”与“AI势能”。 其中在AI绘画领域,Stable D…

内部类练习题

代码: public static void main(String[] args) {A anew A();a.f(); } class A{private String name"A";public void f(){class B{private String name"B";public void show(){System.out.println("A姓名为:"A.this.name…

智慧校园实训管理:打造高效实验项目管理系统

在智慧校园的实训管理框架中,实验项目管理功能是培养学生实践能力和创新精神的关键一环。这一功能通过数字化手段,实现了实验项目的全流程管理,从项目设计、资源调配、过程监控到成果评估,确保了实训活动的高效开展和教学质量的稳…

LabVIEW打开的视频格式IMAQ AVI Open

LabVIEW打开的视频格式IMAQ AVI Open LabVIEW所支持的视频解码器是有限的,不能支持所有的视频解码器。如果解码器选择的不正确,会出现的错误。 错误提示信息如下: Error -1074396009 occurred at IMAQ AVI Open Possible reason(s): An inter…

人工智能大模型发展带来的风险挑战和对策

经过近70年的发展,人工智能技术发展经历了三次起伏,2022年以来,以ChatGPT、Sora等为代表的预训练大模型持续取得突破,推动着人工智能技术从感知向认识,从分析判断式向生成式,从专用向通用进入快速发展的新阶…

提供一个下载国外DockerHub镜像的办法

由于众所周知的一些问题,国内现在下载国外的镜像比较难。尤其是比较新的版本的时候。 比如阿里云加速器的镜像库,skywalking-oap的最新版本也只有8.9,有时候不满足业务需要。官网目前最新10.0.1。很多情况下我们需要9以上版本。 提供几个办…

tomcat使用问题:安装后无法访问localhost:8080

一、tomcat 未启动 所以http://localhost:8080打不开; 二、环境变量未配置 tomcat图标显示已启动,但http://localhost:8080还是打不开,可能是环境变量没有配置好,关于怎么配置环境变量网上到处都是,一下仅供参考: …

halcon_C#联合halcon打开摄像头

1. 创建halcon项目 -> 2.测试连接 -> 3. 在halcon中打开摄像头成功 -> 4. 插入代码 -> 5. 导出为.cs文件 6. 创建VS项目 -> 7.将action部分代码嵌入winform -> 8. 编写代码 -> // 导入HalconDotNet命名空间,这是用于Halcon图像处理的…

MySQL存储引擎和

MySQL存储引擎 在数据库中保存的是一张张有着千丝万缕关系的表,所以表设计的好坏,将直接影响着整个数据库。而在设计表的时候,最关注的一个问题是使用什么存储引擎。MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种…

redis面试(四)ZSet数据结构

Sorted Set 有序集合ZSet,但是有序集合的英文明明是sorted sets。 那这个“Z”代表什么意思,这点官网没有解释,但是gitHub上有人问过,作者是这样回答的 Hello. Z is as in XYZ, so the idea is, sets with another dimension: t…

Selenium与WebDriver:Errno 8 Exec格式错误的多种解决方案

概述 在使用Selenium和WebDriver进行网页自动化时,可能会遇到各种错误。其中一个常见问题是执行格式错误(Errno 8 Exec format error)。这个错误通常在运行ChromeDriver时出现,错误提示涉及路径中的某个文件,如THIRD_…

WordPress建站教程:零基础新手小白如何B2B外贸建站

如果你想通过独立站拿询盘获取订单,那么必须先要有一个自己的网站,所以建站是你绕不过去的一件事。对于零基础的新手小白来说,如何从零开始搭建一个B2B外贸网站呢?本文将为你提供一份详细的WordPress建站教程,帮助你从…

NodeJS云观影应用系统-计算机毕业设计源码60580

摘 要 随着互联网与移动互联网迅速普及,网络上的电影娱乐信息数量相当庞大,人们对获取感兴趣的电影娱乐信息的需求越来越大,个性化的基于Vue框架实现云观影应用系统成为一个热门。然而电影信息的表示相当复杂,因此需要开发一个基于Vue框架实…

Navicat for MySQL 17 实现更明智的业务决策

5 月 12 日,Navicat 对现有产品进行了几项重大更新,包括 Navicat Premium、Navicat BI 和 Navicat Data Modeler。最受欢迎的 Navicat 工具之一,Navicat for MySQL,也得到了新的更新,获得了许多与 Navicat Premium 相同…

PostgreSQL——查询扫描介绍

顺序扫描 概述 顺序扫描(Sequential Scan)是PostgreSQL中一种基本的数据检索方式,它通过按顺序读取表中的所有页面来查找满足查询条件的记录。这种方式不依赖于索引,因此在某些情况下可能是唯一的选择,尤其是当表没有…