本文深入解析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 方法可满足日常需求。
对象复制涉及复杂因素,后续将另文专门整理。
总结
本文内容旨在为学习或工作提供参考,如有疑问欢迎留言交流,感谢支持。