JS深浅拷贝
为什么使用深浅拷贝
在JS中我们经常会遇到一个数据赋值,但是又不符合真正意义上的数据赋值的问题。这个问题产生的原因又是什么呢?这就先要了解一下JS的数据类型了,在JS中数据类型分为基本数据类型和引用数据类型两大派系。众所周知基本数据类型存储的位置就是栈中,以key=>value的形式去存储的,每一个value都对应一个key,但是在引用数据类型中他的存储结构并不是栈而是堆,在堆中堪比一个空间将数据放入,然后这个时候生成一个地址,再将这个地址放入栈中,以key=>value的形式存储。那么问题来了,如果将引用数据类型赋值给另一个变量实际上是将这个地址赋值给了另一个变量。那在修改这个引用数据类型的同时,实际上整堆中的数据就会被修改,其他引用该地址的变量数据也会发生改变,这就会导致程序出现紊乱。怎么解决呢?
浅拷贝
简单理解就是他只拷贝对象数据的第一层或者只是一个赋值的操作并没有将地址发生改变
- 案例
function shallowClone() {
var obj1 = { a: 1, b: 2, c: 3 };
var obj2 = { d: 4, e: 5, f: 6 };
for(var attr in obj2){
obj1[attr] = obj2[attr];
}
return obj1;
}
深拷贝
深拷贝是完全创建一个新的地址的存储空间,同时可以多次递归形式的去拷贝数据
- 案例(普通版本)
function deepCLone(obj) {
var _obj = {};
for (var attr in obj) {
_obj[attr] = obj[attr];
}
return _obj;
}
// 这个返回结果的数据就是地址完全不一样
var obj = deepCLone({ a: 1, b: 2 });
console.log(obj);
- 案例(递归形式拷贝)
function deepClone(obj) {
var _obj = {};
for (var attr in obj) {
for (var attr in obj) {
// 如果不是引用数据类型我们直接复制就行了 如果是引用数据类型我们需要判断然后创建一个新的对象在进行赋值
if (typeof obj[attr] === "object" && obj[attr] !== null && obj[attr].constructor && obj[attr].constructor === Object) {
// 是对象
_obj[attr] = deepClone(obj[attr]);
} else {
_obj[attr] = obj[attr];
}
}
return _obj;
}
}
var obj = {
a: 1,
b: {
str: "hhhh"
}
}
var newObj = deepClone(obj);
console.log(newObj, newObj.b === obj.b) // false
- 案例(拷贝数组)
function deepClone(obj, type) {
var _content = type === "array" ? [] : {};
for (var attr in obj) {
for (var attr in obj) {
// 如果不是引用数据类型我们直接复制就行了 如果是引用数据类型我们需要判断然后创建一个新的对象在进行赋值
if (typeof obj[attr] === "object" && obj[attr] !== null && obj[attr].constructor && obj[attr].constructor === Object) {
// 是对象
_content[attr] = deepClone(obj[attr]);
} else if (Array.isArray(obj)) {
_content[attr] = deepClone(obj[attr], "array");
}
else {
_content[attr] = obj[attr];
}
}
return _content;
}
}
var obj = {
a: 1,
b: [1, 2, 3, 4, 5],
c: {
str: "hello"
}
}
var newObj = deepClone(obj);
console.log(newObj);
- 案例(深拷贝黑科技)
// 函数在拷贝过程中怎么处理 这时候有个滑头的操作
var obj1 = {
foo : function(){
console.log(1);
}
}
// 将函数先转成字符串在使用eval将可执行的js代码成功转换
var newFn = eval("("+obj1.foo.toString()+")");
console.log(newFn)
// 黑科技深拷贝 一般人我不告诉他
var obj1 = {
a: 1,
b: 2,
c: {
str: "hello"
},
d: [1, 2, 3, 4],
f: function () {
console.log(1);
}
}
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj2); // 虽然这个黑科技好用但是也要慎重使用因为是ES5中支持的而且有的时候在处理数据的转换的时候会出现异常情况
总结
我觉得深浅拷贝的含义并不难理解,只需要搞懂JS的数据类型的存储结构和特点就可以轻松理解什么是深浅拷贝了。