你还在傻傻的认为传递分为值传递和引用传递吗?

前言

这篇文章是本人在读红宝书(第四版)4.1.3节-传递参数时引发的思考产出的最终结果,记录一下思考的过程。因为函数传参的过程其实就是变量赋值的过程,所以本文全部用变量赋值举例。若各位大佬有不同见解,欢迎探讨!

先说结论:在传递操作中只有值传递,没有引用传递。

我们大多都是把这两个概念混淆在一起,所以会觉得存在引用传递,接下来我们先区分传递和访问两种概念。

值传递是指在变量赋值的过程,并且会将原变量的值复制一份出来赋给新变量,两个变量互不相干。

ini 复制代码
const a = 1;  // 这是一次值传递操作
let b = a; // 这也是一次值传递操作
b = 2;
console.log(a); // 1  修改b的值不会影响a

访问是指读取变量值的过程,分为按值访问、按引用访问

按值访问

其实值传递的过程中会涉及到访问的操作,比如我有一个变量a值为1,现在要将a的值赋值给一个新的变量b,首先得拿到a的值才能赋值给b,在访问a的具体值的过程所使用的访问方式就是按值访问。

ini 复制代码
const a = 1;  
let b = a; // 这里需要先拿到a的值,才能赋值给b
按引用访问

按引用访问概念和按值访问差不多,我们都知道像对象、数组等等一些复杂的数据类型是存储在堆内存中的。所以我们的变量中存的是存在堆内存中数据的地址,访问该变量时会根据变量对应的内存地址去堆内存中查找对应的数据,这个访问方式称为按引用访问。

ini 复制代码
const obj = {
    a: 1
};  
const obj1 = obj; // 这里需要先拿到obj的值,也就是该对象在堆内存中的地址,才能赋值给obj1

可以看到我们在将obj的对象赋值给obj1时,实质上是复制了一份地址给obj1,因此我们可以通过更改变量的地址来使其脱离原来对象的引用。

ini 复制代码
const obj = {
  a: 1,
  b: 2,
};
let obj1 = obj;
obj1.a = "a";
console.log(obj); // { a: 'a', b: 2 }
obj1 = {}
obj1.a = "a1"
console.log(obj); // { a: 'a', b: 2 }
console.log(obj1);  // { a: 'a1' }

上述代码第一个打印结果证明obj1和obj操作的是同一个对象,因为他们所对应的是同一个堆对象地址,地址相同,所以对象相同。

接下来将obj1赋值为空对象,我们可以先理一下这一步会发生什么。首先有一个空对象,就会在堆内存中开辟一个新的空间来存储这个空对象,然后将这个新空间的地址赋值给obj1。此时obj1和obj对应的对象内存地址已经不一致了,所以接下来对obj1对象的操作不会再影响obj的对象。

所以我们通过给obj1赋值新对象的方式,使其与obj的对象脱离绑定,互不影响,这不就是值传递的概念么。

结论:只有值传递,没有引用传递!

相关推荐
子兮曰11 分钟前
后端字段又改了?我撸了一个 BFF 数据适配器,从此再也不怕接口“屎山”!
前端·javascript·架构
颜酱2 小时前
一步步实现字符串计算器:从「转整数」到「带括号与优化」
javascript·后端·算法
比尔盖茨的大脑2 小时前
事件循环底层原理:从 V8 引擎到浏览器实现
前端·javascript·面试
卓卓不是桌桌2 小时前
如何优雅地处理 iframe 跨域通信?这是我的开源方案
javascript·架构
滕青山3 小时前
腾讯域名拦截查询 在线工具核心JS实现
前端·javascript·vue.js
进击的尘埃3 小时前
TypeScript 协变与逆变:你的泛型组件 Props 为什么总是类型报错?
javascript
helloweilei3 小时前
javascript 结构化克隆
javascript·node.js
龙猫不热3 小时前
从 0 手写 Promise:拆解 Promise 链式调用的实现原理
前端·javascript·面试
wuhen_n5 小时前
TypeScript 强力护航:PropType 与组件事件类型的声明
前端·javascript·vue.js
wuhen_n5 小时前
组件设计原则:如何设计一个高内聚、低耦合的 Vue 组件
前端·javascript·vue.js