关于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的基础了解的还是不够深,所以才产生了这样的错误,引以为戒引以为戒!同时问了一些身边的同事,也有一些人并不了解这个,对于预期的结果还是会有错误判断,所以将这个过程进行整理,同大家进行分享,共同进步,当然如果文中有任何错误,请大家及时指出,向大家学习!最后,新年将至,提前祝大家:新年快乐!暴富!暴富!暴富!

相关推荐
wusp19941 小时前
v-model 和 :value 的深度解析
前端·javascript·vue.js
2501_944424121 小时前
Flutter for OpenHarmony游戏集合App实战之记忆翻牌表情图案
开发语言·javascript·flutter·游戏·harmonyos
pas1361 小时前
34-mini-vue 更新element的children-双端对比diff算法
javascript·vue.js·算法
ashcn20011 小时前
websocket测试通信
前端·javascript·websocket
吃吃喝喝小朋友2 小时前
JavaScript文件的操作方法
开发语言·javascript·ecmascript
Trae1ounG2 小时前
模块间通信解耦
javascript
2501_944526422 小时前
Flutter for OpenHarmony 万能游戏库App实战 - 知识问答游戏实现
android·开发语言·javascript·python·flutter·游戏·harmonyos
卿着飞翔2 小时前
Vue使用yarn进行管理
前端·javascript·vue.js
夏天想2 小时前
vue通过iframe引入一个外链地址,怎么保证每次切换回这个已经打开的tab页的时候iframe不会重新加载
前端·javascript·vue.js
军军君012 小时前
Three.js基础功能学习十一:动画与音频
前端·javascript·3d·js·threejs·三维