目录
一、先上面试的答案:
浅拷贝:只拷贝源数据的第一层,修改拷贝的数据第一层,源数据也不会发生改变。修改拷贝的数据第二层源数据会发生改变。源数据的修改,拷贝的数据就会
深拷贝:
二、浅拷贝
-
浅拷贝的实现方式1
直接上案例分析
function simpleClone(initalObj) {
var obj = {}; //定义对象 obj 为空对象
for ( var i in initalObj) { //循环initalObj 里的每个键值对 赋值 给对象的obj对象
obj[i] = initalObj[i];
}
return obj; // 返回赋值好的 obj 这个对象
}
var obj = {
a: "hello",
b:{
a: "world",
b: 21
},
c:["Bob", "Tom", "Jenny"],
d:function() {
alert("hello world");
}
};
var cloneObj = simpleClone(obj);
console.log(cloneObj.a);
console.log(cloneObj.b);
console.log(cloneObj.c);
console.log(cloneObj.d);
//更改拷贝对象中的a,b,c,d,看看源对象是否变化
cloneObj.a = "changed";
cloneObj.b.a = "changed";
cloneObj.b.b = 25;
cloneObj.c = [1, 2, 3];
cloneObj.d = function() { alert("changed"); };
console.log(obj.a); //hello
console.log(obj.b); //{a:"changed",b:25},事实上就是只有对象是拷贝的引用类型
console.log(obj.c); //['Bob','Tom','Jenny']
console.log(obj.d); //...alert("hello world")
对上述代码分析:
总结:
浅拷贝就是拷贝了一层,除了对象是拷贝的引用类型,其他都是直接将值传递,有自己的内存空间的。更改第一层数据是无法修改源对象的。
- 浅拷贝的实现方式2:Object.assign方法
Object.assign是ES6的新函数。Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
var obj1 = {
a: "hello",
b: {
a: "hello",
b: 21}
};
var cloneObj1= Object.assign({}, obj1);
cloneObj1.a = "changed";
cloneObj1.b.a = "changed";
console.log(obj1.a); //hello
console.log(obj1.b.a); // "changed"
三、深拷贝
复制的对象的第一层数据还是第二层数据的修改,不改变源数据。
/* 深拷贝 */
// 1.Array 数组深拷贝
// 1.1 通过slice方法
// slice()操作数组时,不会对原数组有影响,会产出一个新的数组。
let arr1 = [1, 42, 5, 6]
let arr2 = arr1.slice()
arr2[0] = 100
console.log(arr1) // [1, 42, 5, 6]
console.log(arr2) // [100, 42, 5, 6]
// 1.2 通过concat方法
let arr3 = ['cat', 'dog', 'pig']
let arr4 = [].concat(arr3)
arr3[2] = 'big pig'
console.log(arr3) // ['cat', 'dog', 'big pig']
console.log(arr4) // ['cat', 'dog', 'pig']
// 1.3 通过ES6语法中 …扩展运算符
const fruits = ['1', '2', '3', '4', '5']
const citrus = [...fruits]
fruits[0] = 888
console.log(fruits) //[888, '2', '3', '4', '5']
console.log(citrus) //['1', '2', '3', '4', '5']
// 1.4 通过 Array.from()
const arr5 = ['1', '2', '3', '4', '5']
const A = Array.from(arr5)
arr5[0] = 888
console.log(arr5) //[888, '2', '3', '4', '5']
console.log(A) //['1', '2', '3', '4', '5']
// 2 Object 对象的深拷贝
// 2.1 通过Object.assign()方法
let person = {
name: 'xia',
age: 25,
height: 160,
}
let otherPerson = Object.assign({}, person) //person对象合并{}空对象
person.age = 30
console.log(person) //{name: 'xia', age: 30, height: 160}
console.log(otherPerson) //{name: 'xia', age: 25, height: 160}
// 3 万能转换器(对Array和Object等都适用)
// 前面讲解了 Array和Object的深拷贝方法,但是对于有更深层次的结构关系(数组套数组 数组套对象 对象套对象等),上面的方法就失灵了,可以看下面的例子。
let personArr = [{ name: 'xia' }, { name: 'zhang' }]
let otherPersonArr2 = [...personArr]
personArr[0].name = 'xia xia'
console.log(personArr) //[{ name: 'xia xia' }, { name: 'zhang' }]
console.log(otherPersonArr2) //[{ name: 'xia xia' }, { name: 'zhang' }]
// 这个例子我们可以看出修改了源数据,那么拷贝的新数组也改变了。这种情况下给大家介绍一个万能转换器 JSON.parse(JSON.stringify(obj))深拷贝已有对象,它可以深拷贝多层级的,不用担心嵌套问题。
let jack = {
name: 'jack',
}
console.log(jack) //{name: 'jack'} 这是对象
console.log(JSON.stringify(jack)) //{"name":"jack"} 这个是json字符串
// JSON.parse()将json字符串解析成对象
let obj = { name: '静茹秋叶' }
console.log('obj: ', obj) //obj: {name: '静茹秋叶'}
console.log('json string: ', JSON.stringify(obj)) //json string: {"name":"静茹秋叶"}
let str = JSON.stringify(obj)
console.log(str) //{"name":"静茹秋叶"}
console.log('str to obj: ', JSON.parse(str)) //str to obj: {name: '静茹秋叶'}
let x = JSON.parse(JSON.stringify(obj))
x.name = '庄领'
console.log(obj) //{name: '静茹秋叶'}
console.log(x) //{name: '庄领'}