JavaScript 引用与值传递机制详解及数组对象深拷贝方法

作者:代码拾荒时间:2026-10-23 05:04:52浏览:197

本文深入解析JavaScript中值类型与引用类型的传递机制,通过示例说明基本数据类型与复杂数据类型的区别。重点介绍数组和对象的浅拷贝与深拷贝实现方式,包括ES6展开运算符、Object.assign及lodash库的使用,帮助开发者避免共享引用导致的意外修改。

JavaScript引用与值传递机制

前言

在JavaScript开发中,引用与复制的概念往往容易被忽视,但厘清这一核心概念对于理解变量行为至关重要。

首先回顾基础概念,JavaScript中的不同数据类型在传递时表现各异。

引用类型包括对象、数组和函数。

值类型(复制)主要包括数字和布尔值。

字符串具有特殊性,由于不可变性,讨论其传递引用还是复制数值意义不大,但在比较时显然属于传值比较。

接下来通过具体示例进行详细解析。

首先观察以下基础示例:


let age = 18;
let age2 = age;
console.log(age, age2);

执行后将获得如下输出结果:

18 18

这一结果符合直觉,易于理解。

如果随后修改 age 的值,输出会发生什么变化?


age = 20;
console.log(age, age2);

此时控制台显示:

20 18

上述结果看似正常,但JavaScript中存在例外情况。

然而,JavaScript 存在例外情况:对于 integer、string、boolean 等普通数据类型,可使用 = 进行变量复制;但对于 array 和 object 数据类型,= 仅产生引用效果。

请参考以下数组示例:


let arr = ['wes', 'bob', 'faker'];
let arr2 = arr;
console.log(arr2, arr);
arr[2] = 'dean';
console.log(arr2, arr);

运行结果如下:

["wes", "bob", "faker"] ["wes", "bob", "faker"] ["wes", "bob", "dean"] ["wes", "bob", "dean"]

可以看出,当 arr 内容改变时,arr2 也随之改变。

这表明 arr2 并未复制 arr 的值,而是引用了同一内存地址,两者指向相同数据。

对象类型表现一致:


let obj = {
 age: 19,
 name: 'like',
 last: 'jam'
};
let obj2 = obj;
console.log(obj, obj2);
obj.age = 50;
console.log(obj, obj2);

输出结果为:

{age: 19, name: "like", last: "jam"} {age: 19, name: "like", last: "jam"} {age: 50, name: "like", last: "jam"} {age: 50, name: "like", last: "jam"}

数组与对象的复制方法

那么如何正确复制数组和对象?

以下是几种数组复制方法:

方法1:


let arr2 = [].concat(arr);

方法2:


let arr2 = arr.slice();

方法3:


let arr2 = Array.from(arr);

方法4:


let arr2 = [...arr];

实际开发中,方法3和方法4更为常用。方法1和方法2虽较取巧,但均能实现数组复制目的。

注:[...arr] 为ES6语法特性。

对象复制方法如下:

方法1:


let obj2 = Object.assign({}, obj);

方法2:


let obj2 = {...obj};

浅拷贝的局限性

上述方法1和2存在局限,仅能复制对象的第一层属性。

验证示例如下:


let obj = {
 number: 12,
 name: {
  first: 'bob',
  last: 'evil'
 }
};
let obj2 = Object.assign({}, obj);
obj.number = 50;
console.log(obj, obj2);

初始状态输出:

obj = { number: 50, name: { first: 'bob', last: 'evil' } }

obj2 = { number: 12, name: { first: 'bob', last: 'evil' } }

若修改第二层属性值:


obj.name.first = 'sam';
console.log(obj, obj2);

obj = { number: 50, name: { first: 'sam', last: 'evil' } }

obj2 = { number: 12, name: { first: 'sam', last: 'evil' } }

可见对象第二层仍保持引用关系,未实现真正复制。

完整对象复制方案

如何完整复制一个对象?

最简便方式是使用第三方库lodash,其提供的 clone 和 deepclone 方法可满足日常需求。

对象复制涉及复杂因素,后续将另文专门整理。

总结

本文内容旨在为学习或工作提供参考,如有疑问欢迎留言交流,感谢支持。

作者最新文章