关于js函数中修改复杂数据类型的问题

前言

临近过年放假,这段时间需求量也是逐渐减少,产品的态度也是"有什么事情年后再说"。于是笔者在做完需求的闲暇,还是打开了吃灰的leetcode,点击筛选困(jian)难(dan)、点开第一题、ok简单开始写、点击运行、失败.....

问题复现

OK,其实是一道很简单的题,题目如下:

题目要求函数不return,只修改nums1,OK,经过长达10s的思索,自信写下

js 复制代码
 /**
 * @param {number[]} nums1
 * @param {number} m
 * @param {number[]} nums2
 * @param {number} n
 * @return {void} Do not return anything, modify nums1 in-place instead.
 */
var merge = function(nums1, m, nums2, n) {
    nums1 = nums1.slice(0,m).concat(nums2)
    nums1.sort((a,b) => a - b)
};

运行、失败。 查看测试用例,发现nums1值未被修改,仍旧为修改前的原值。第一时间判断,是不是这样的写法无法修改函数外部的原值。然后尝试使用其他写法。

其实这个时候还是没有太好的想法,想了一下如果赋值的方式不行,那使用js的能够修改原数组的方法能不能行,于是尝试使用splice。然后:啊?splice参数是啥来着?默默打开MDN......(大家还是没事得多记记这些方法,不要像我一样,我是笨蛋= =)

找到splice用法后,尝试改写这个函数。

js 复制代码
/**
 * @param {number[]} nums1
 * @param {number} m
 * @param {number[]} nums2
 * @param {number} n
 * @return {void} Do not return anything, modify nums1 in-place instead.
 */
var merge = function(nums1, m, nums2, n) {
    nums1.splice(m, nums1.length - m, ...nums2);
    nums1.sort((a,b) => a - b)
};

ok, 点击运行、运行通过!

接下来就要好好思考一下,为什么赋值的方式无法更改函数外原数据,而是不是splice这类修改原数据的方式就可以?js的函数传参,传的是什么东西?

于是开始研究,先是尝试了几种类似splice这类能够修改原数据的方法,发现都可以修改到,不禁疑惑🤔,如果函数传参传的是值,为什么splice会修改到原数据?而如果传的是地址,为什么使用slice创建了一个新的数组,并赋值,不会覆盖原来的地址?带着疑惑我开始查阅相关的文档......(这里省略一千字)

OK直接上结论

原来在js中,虽然函数的参数是按值传递的,但是对于引用类型的值,传递的其实是引用的副本。类似于图中所示:

实际函数传参是将地址复制了一份作为值传进来,当我们使用splice这类方法时,js会顺着地址去内存中找到对应的值,并对其进行修改,那么我们在外面打印这个数组时,看到的自然是修改后的数据。

而当我们使用赋值的方式,尝试为它赋值一个新地址的时候,就会像这样:

实际上当使用slice之类的方法时,会创建一个新的引用类型,并将引用地址的副本进行了覆盖,新的地址指向了新创建的引用类型值,那么我们再去外面打印这个数组时,得到的自然是未修改的数据。

寄言

其实是一题很简单的题目,可能因为笔主对于js的基础了解的还是不够深,所以才产生了这样的错误,引以为戒引以为戒!同时问了一些身边的同事,也有一些人并不了解这个,对于预期的结果还是会有错误判断,所以将这个过程进行整理,同大家进行分享,共同进步,当然如果文中有任何错误,请大家及时指出,向大家学习!最后,新年将至,提前祝大家:新年快乐!暴富!暴富!暴富!

相关推荐
摸鱼的春哥11 分钟前
惊!黑客靠AI把墨西哥政府打穿了,海量数据被黑
前端·javascript·后端
小兵张健14 分钟前
Playwright MCP 截图标注方案调研(推荐方案1)
前端·javascript·github
我叫黑大帅3 小时前
Vue3和Uniapp的爱恨情仇:小白也能懂的跨端秘籍
前端·javascript·vue.js
None3213 小时前
【NestJs】使用Winston+ELK分布式链路追踪日志采集
javascript·node.js
Qinana4 小时前
从代码到智能体:MCP 协议如何重塑 AI Agent 的边界
前端·javascript·mcp
Marshall1514 小时前
zzy-scroll-timer:一个跨框架的滚动定时器插件
前端·javascript
明月_清风6 小时前
打字机效果优化:用 requestAnimationFrame 缓冲高频文字更新
前端·javascript
明月_清风6 小时前
Markdown 预解析:别等全文完了再渲染,如何流式增量渲染代码块和公式?
前端·javascript
程序猿的程19 小时前
开源一个 React 股票 K 线图组件,传个股票代码就能画图
前端·javascript
大雨还洅下20 小时前
前端JS: 虚拟dom是什么? 原理? 优缺点?
javascript