现象:直接用
=
的方式把一个对象赋值给另一个对象,会导致修改新对象时,原对象也发生变化var obj1 = {'name': '1111'}; var obj2 = obj1; obj2.name = '2222'; console.log(obj1.name); //'2222'
- 原因:JavaScript 中对象的赋值是默认引用赋值的(两个对象指向相同的内存地址)
一、Object.assign()
拷贝对象
代码演示
// 使用 Object.assign() 方法复制对象
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj2.a = 2;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}
不足之处
- 可以看到当修改
obj2.b.c
的值时,原对象obj1.b.c
也跟着发生了变化,Object.assign()
只是让对象里第一层的数据没有了关联性,但是对象内的对象则跟被复制的对象有着关联性的。 Object.assign(obj)
--浅拷贝Object.assign({},obj)
--只有第一层深拷贝 (ES6中扩展运算符...也是如此)
二、JSON.parse(JSON.stringify(obj))
代码演示
var function cloneObjectFn (obj){
return JSON.parse(JSON.stringify(obj))
}
var obj1={a:2,b{c:0}}
var obj2=cloneObjectFn(obj1)
console.log(obj2) // {a:2,b{c:0}}
不足之处
使用场景限制:obj属性不能是function、RegExp等,JSON序列化时会造成属性丢失:
三、原生JS实现深拷贝
// 定义一个深拷贝函数 接收目标target参数
function deepClone(target) {
// 定义一个变量
let result;
// 如果当前需要深拷贝的是一个对象的话
if (typeof target === 'object') {
// 如果是一个数组的话
if (Array.isArray(target)) {
result = []; // 将result赋值为一个数组,并且执行遍历
for (let i in target) {
// 递归克隆数组中的每一项
result.push(deepClone(target[i]))
}
// 判断如果当前的值是null的话;直接赋值为null
} else if (target === null) {
result = null;
// 判断如果当前的值是一个RegExp对象的话,直接赋值
} else if (target.constructor === RegExp) {
result = target;
} else {
// 否则是普通对象,直接for in循环,递归赋值对象的所有值
result = {};
for (let i in target) {
result[i] = deepClone(target[i]);
}
}
} else {
// 如果不是对象的话,就是基本数据类型,那么直接赋值
result = target;
}
// 返回最终结果
return result;
}
PS. JS中function
也是引用类型,但是函数名
仅仅是指向该函数的指针
,换句话说,一个函数可能会有多个名字
function sum(num1, num2){
return num1 + num2;
}
console.log(sum(10, 10));// 20
var anotherSum = sum; // 此时有两个变量sum和anotherSum同时指向该函数(该函数此时有俩名字)
console.log(anotherSum(10, 10));// 20
sum = null; // sum置为空后,此时只有anotherSum指向该函数(该函数只有一个名字anotherSum)
console.log(anotherSum(10, 10));// 20
如上:代码中首先定义了一个名为sum
的函数,用于求两个数的和。然后,又声明了变量anotherSum
,赋值为sum
,此时anotherSum
和sum
就指向了同一个函数,因此anotherSum()
也正常返回了结果。即使切断sum
与函数对象的引用关系,也不会影响anotherSum
四、第三方提供的深拷贝方法
- 写angularJS的时候用
angular.copy()
- 现在常用的是
lodash.cloneDeep()
,当然类似方法还有很多,符合自己习惯就好 - 更多详细内容请参考:https://www.cnblogs.com/c2016...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。