js 有两种数据类型,基础数据类型和引用数据类型;基础数据类型都是按值访问的,我们可以直接操作保存在变量中的实际的值。而引用类型如Array,
我们不能直接操作对象的堆内存空间。引用类型的值都是按引用访问的,即保存在变量对象中的一个地址,该地址与堆内存的实际值相关联。
1.浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存;
浅拷贝是指只复制一层对象,当对象的属性是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化
案例:
// 引用类型
let obj1 = { a: 10, b: 20, c: 30 };
let obj2 = obj1;
obj1.b = 60;
// 或
// obj2.b = 50;
console.log(obj1);
console.log(obj2);
let array1 = [0, 1, 2, 3, 4];
let array2 = array1;
console.log(array1 === array2);
array1[0] = 1;
console.log(array1, array2);
2.深拷贝:复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变。
基础数据类型
let a = 'zjl';
let b = a;
a = 'zmf';
// 或
// b='dwb';
console.log('a:' + a + ' ' + 'b:' + b);
所以当你此时修改a='zmf',对b并不会造成影响,因为此时的b已自食其力,不受a的影响了。当然,let a='zjl',b=a;虽然b不受a影响,但这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。
// 这里再次强调,深拷贝,是拷贝对象各个层级的属性,可以看个例子。JQ里有一个extend方法也可以拷贝对象,我们来看看
let array3 = [1, 3, 4, 2, 5];
let array4 = array3.slice();
array3[0] = 10;
array4[0] = 20;
console.log(array3, array4);
// 那是不是说slice方法也是深拷贝了,毕竟array4也没受array3的影响,上面说了,深拷贝是会拷贝所有层级的属性,还是这个例子,我们把array3改改
let array5 = [1, 3, 5, 2, [2, 3], 4, 5];
let array6 = array5.slice();
array5[4][0] = 4;
// array6[4][0]=5;
console.log(array5, array6);
// 拷贝的不彻底啊,array6对象的一级属性确实不受影响了,但是二级属性还是没能拷贝成功,仍然脱离不了array5的控制,说明slice根本不是真正的深拷贝。
下面就来说说深拷贝的一些方法
1.递归
看这个之前可以去看看递归算法
let json1 = { "name": "shauna", "age": 18, "arr1": [1, 2, 3, 4, 5], "string": 'got7', "arr2": [1, 2, 3, 4, 5], "arr3": [{ "name1": "shauna" }, { "job": "web" }] };
let json2 = {};
function copy(obj1, obj22) {
let obj2 = obj22 || {};
for (let name in obj1) {
// console.log(obj1[name])
if (typeof obj1[name] === "object") {
obj22[name] = (obj1[name].constructor === Array) ? [] : {};
copy(obj1[name], obj22[name]);
} else {
obj22[name] = obj1[name];
}
}
return obj22;
}
json2 = copy(json1, json2);
json1.arr1.push(6);
console.log(json1.arr1, json2.arr1);
// 1.2
function deepClone(obj3) {
let objClone = Array.isArray(obj3) ? [] : {};
if (obj3 && typeof obj3 === "object") {
for (key in obj3) {
if (obj3.hasOwnProperty(key)) {
//判断ojb子元素是否为对象,如果是,递归复制
if (obj3[key] && typeof obj3[key] === "object") {
objClone[key] = deepClone(obj3[key]);
} else {
//如果不是,简单复制
objClone[key] = obj3[key];
}
}
}
}
return objClone;
}
let obja = [1, 2, 3, 4],
objb = deepClone(obja);
obja[0] = 2;
console.log(obja, objb);
2.JSON对象的parse和stringify 但这种方法的缺陷是会破坏原型链,并且无法拷贝属性值为function的属性
function JsonCopy(objj) {
let _objj = JSON.stringify(objj);
_objj = JSON.parse(_objj)
return _objj;
}
let jsona = [0, 1, [2, 3], { function() { console.log(false) } }, 4]; //这里加了function这个对象,这个对象不能被拷贝过去
let jsonb = JsonCopy(jsona);
jsona[2][1] = 6;
jsonb[2][1] = 7;
console.log(jsona, jsonb);
3.es6 Object.assign():Object.assign()是一种可以对非嵌套对象进行深拷贝的方法,如果对象中出现嵌套情况,那么其对被嵌套对象的行为就成了普通的浅拷贝。
let zjl = {
a: 1,
b: 2,
c: {
d: 1,
}
}
let zmf = {};
Object.assign(zmf, zjl);
zjl.a++;
zjl.a === 2 //true
zmf.a === 1 //true
zjl.c.d++;
zjl.c.d === 2 //true
zmf.c.d === 1 //false
zmf.c.d === 2 //true
4.JQ的extend方法
$.extend([deep], target, object1[, objectN])
deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝
target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。
object1 objectN可选。 Object类型 第一个以及第N个被合并的对象。
let jqa = [0, 1, [2, 3], 4],
jqb = $.extend(true, [], jqa);
jqa[0] = 1;
jqa[2][0] = 1;
console.log(a, b);