数据的深浅拷贝和赋值
1、赋值
- 对于基本数据类型:赋值的话会直接在栈空间开辟一个内存空间,用来存储被复制过来的数据值。
- 对于引用数据类型:赋值的话会直接在栈空间开辟一个内存空间,用来存储赋值数据对应的堆中的存储地址。
var userName = '闷倒驴';
var user = {userName:'闷倒驴',sex:'女',body:{weight:'50kg',height:'160'}}
// 赋值
var userCopy = user;
user.sex = '男';
user.body.weight = '100斤';
console.log(user);
console.log(userCopy);
修改user的sex、body.weight的数据值后,user和userCopy地址不变,但是里面的数据值都会改变
2、 浅拷贝
2.1浅拷贝原理
- 对于引用数据类型,栈堆都会开辟一个新的空间,用来存储数据,堆空间开辟一个新空间,用来存储从源数据那赋值过来的数据,那么新开的栈中存储的是新开堆中的内存地址。
- 对于基本数据类型,同基本数据类型的赋值一样。
var user = {userName:'闷倒驴',sex:'女',body:{weight:'50kg',height:'160'}}
// 浅拷贝
var userCopy = Object.assign({}, user);
user.sex = '男';
user.body.weight = '100斤';
修改user里面的基本数据不会对userCopy里面的数据产生影响,而修改user里面的引用数据类型即上例中的body.weight会对userCopy里面的body.weight数据产生影响。
修改后
2.2 可以实现浅拷贝的方法
方法一 Object.assign()
Object.assign()方法可以把任意多个源对象自身可枚举的属性浅拷贝到目标对象,然后返回目标对象。
let obj1 = { person: { name: "kobe", age: 41 }, sports: 'basketball' };
let obj3 = {aaa:3333}
let obj2 = Object.assign({}, obj1,obj3);
obj2.person.name = "wade";
obj2.sports = 'football'
console.log(obj1);
console.log(obj2)
方法二 函数库lodash的_.clone方法
该函数库也有提供_.clone用来做浅拷贝。
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.clone(obj1);
console.log(obj2);
obj1.a = 0;
obj1.b.f.g = 1000;
console.log(obj1);
console.log(obj2);
方法三 展开运算符 (…)
let obj1 = { name: '王美丽', address: { x: 100, y: 100 } }
let obj2 = { ...obj1 }
obj1.address.x = 200;
obj1.name = '闷倒驴'
console.log('obj2', obj2)
方法四 Array.prototype.concat()
let arr = [1, 3, {
username: '王美丽'
}];
let arr2 = arr.concat();
arr2[2].username = '闷倒驴';
console.log('arr',arr);
console.log('arr2',arr2);
方法五 Array.prototype.slice()
let arr = [1, 3, {
username: ' 王美丽'
}];
let arr3 = arr.slice();
arr3[2].username = '闷倒驴'
console.log('arr:',arr);
console.log('arr3:',arr3);
3、深拷贝
3.1 深拷贝原理
- 对于引用数据类型,栈和堆空间都会开辟一个内存空间,栈中存储堆中新开的内存地址,堆中存储的数据和源数据一样,但是二者没什么联系
var userName = '闷倒驴';
var user = { userName: '闷倒驴', sex: '女', body: { weight: '50kg', height: '160' } }
// 深拷贝
var userCopy = JSON.parse(JSON.stringify(user));
user.sex = '男';
user.body.weight = '100斤';
console.log(user);
console.log(userCopy);
3.2 实现深拷贝的方法
方法一 JSON.parse(JSON.stringify())
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let arr = [1, 3, {
username: '闷倒驴'
}];
let arr1 = JSON.parse(JSON.stringify(arr));
arr1[2].username = '王美丽';
console.log(arr, arr1)
</script>
</body>
</html>
注意:使用该方法会有一个缺点,该方法虽然可以实现数组或对象的深拷贝,但是不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。
- 函数:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let arr = [1, 3, {
username: '闷倒驴'
},function(){
var aa = 111111
}];
let arr1 = JSON.parse(JSON.stringify(arr));
arr1[2].username = '王美丽';
console.log(arr, arr1)
</script>
</body>
</html>
- 正则
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let arr = [1, 3, {
username: '闷倒驴'
},new RegExp("ab+c")];
let arr1 = JSON.parse(JSON.stringify(arr));
arr1[2].username = '王美丽';
console.log(arr, arr1)
</script>
</body>
</html>
方法二 函数库lodash的_.cloneDeep方法
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 2 } },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
obj1.b.f = '改变f属性';
console.log(obj1,obj2);// false
方法三 JQuery.extend()方法
使用该方法需要引入JQuery
// $.extend(deepCopy, target, object1, [objectN])//第一个参数为true,就是深拷贝
var jsdom = require('jsdom');
const { JSDOM } = jsdom;
const { window } = new JSDOM();
var $ = jQuery = require('jquery')(window);
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false