浅拷贝与深拷贝
2018 javascriptJavaScript 变量有两种不同数据类型:基本类型和引用类型。
基本数据类型是按值访问,可以直接操作保存在变量中的实际值。引用类型的值是保存在堆内存中的对象,JavaScript 不能直接操作对象的内存空间,实际操作的是对象的引用。在传递的时候,基本类型是传值,引用类型是传址。所以,浅拷贝与深拷贝只针对于引用类型这种对象。
浅拷贝与深拷贝
浅拷贝:浅拷贝只拷贝对象的引用地址,并没有创建新的对象,并没有开辟新的堆内存。拷贝出来的变量是同一个引用地址,指向同一个对象。
深拷贝:深拷贝是对引用的对象全部进行拷贝。在内存中创建了新的对象,拷贝出来的变量指向不同的引用地址,指向不同的对象。
浅拷贝的示例
- 赋值操作
var arr = [1, 2, 3, 4];
var obj = { a: 'a', b: 'b' };
var arrCopy = arr;
var objCopy = obj;
arrCopy[0] = 0;
objCopy.a = 'aa';
log(arr, arrCopy); //[0, 2, 3, 4], [0, 2, 3, 4]
log(obj, objCopy); //{ a: "aa", b: "b" }, { a: "aa", b: "b" }
特别的浅拷贝
当数据只有一层的时候,该方法可以当作深拷贝使用。当数据超过一层时候,只能用作浅拷贝。
- Array.slice() –常用作数组
var arr = [1, 2, 3, 4];
var arrCopy = arr.slice();
arrCopy.push(5);
log(arr, arrCopy);
//[1, 2, 3, 4], [1, 2, 3, 4, 5]
var arr = [1, 2, 3, 4, [10, 11]];
var arrCopy = arr.slice();
arrCopy[4].push(12);
log(arr, arrCopy);
//[1, 2, 3, 4, [10, 11, 12]], [1, 2, 3, 4, [10, 11, 12]]
- Ojbect.assign() –常用作对象
var obj = { a: 'a', b: 'b' };
var objCopy = Object.assign({}, obj);
objCopy.a = 'aaa';
log(obj, objCopy);
//{ a: "a", b: "b" }, { a: "aaa", b: "b" }
var obj = { a: 'a', b: 'b', c: { d: 'd' } };
var objCopy = Object.assign({}, obj);
objCopy.c.d = 'ddd';
log(obj, objCopy);
//{ a: 'a', b: 'b', c: {d: "ddd"} }, { a: 'a', b: 'b', c: {d: "ddd"} }
- 扩展运算符… –数组,对象都常用
var arr = [1, 2, 3, 4];
var obj = { a: 'a', b: 'b' };
var arrCopy = [...arr];
var objCopy = { ...obj };
arr.push(5);
obj.c = 'c';
log(arr, arrCopy); //[1, 2, 3, 4, 5] [1, 2, 3, 4]
log(obj, objCopy); //{ a: "a", b: "b" }, { a: "a", b: "b", c: "c" }
深拷贝
- JSON.parse 和 JSON.stringify
var obj = { a: { b: 'c' } };
var objCopy = JSON.parse(JSON.stringify(obj));
objCopy.a.b = 'd';
log(obj, objCopy); //{ a: { b: "c"} }, { a: { b: "d"} }
局限性:无法转换function
,function
会直接消失掉。
var obj = {
fun: function () {
console.log('hi');
},
};
var objCopy = JSON.parse(JSON.stringify(obj));
log(typeof obj.fun); //"function"
log(typeof objCopy.fun); //"undefined"
-
Jquery 的 extend
-
Lodash 的 cloneDeep
题外话
数组的部分方法原本是不改变原数组的,如 map, filter, find…等等。但是如果数组项是对象的话,且遍历时修改原数组项会修改原数组。
const arr = [1, 2, 3];
const arr2 = [{ value: 1 }, { value: 2 }];
const copy = arr.map((i) => {
i += 1;
return i;
});
const copy2 = arr2.map((i) => {
i.value += 1;
return i;
});
console.log(arr, copy);
// [1, 2, 3] [2, 3, 4]
console.log(arr2, copy2);
// [{ value: 2 }, { value: 3 }] [{ value: 2 }, { value: 3 }]