什么是深拷贝/浅拷贝
- 浅拷贝是创建一个新对象,这个对象具有原始对象属性值。如果属性是基本类型的话,拷贝的就是基本类型。如果属性是引用类型,拷贝的就是引用地址,改变了其中一个对象,就会影响到另外一个对象。
- 深拷贝是将一个对象从内存中完整拷贝了一份,从堆内存中开辟了一个新的区域存放新对象,修改后不会影响原来的对象。
赋值、深拷贝、浅拷贝的区别
- 对象数组赋值给一个新的变量时,其实是赋的内存地址,而不是对象中的数据。所以修改一个将影响另外一个。
1 | var person1 = {
|
2 | name: '张三',
|
3 | age: 20,
|
4 | list: [1, 2, 3]
|
5 | }
|
6 | let arr = [4,5,6]
|
7 | var person2 = person1;
|
8 | person2.age = 22;
|
9 | person2.list = arr;
|
10 | person2.list[0] = '张三';
|
11 | console.log(person1);
|
12 | console.log(person2);
|
13 | console.log(arr);
|
实现的方式
浅拷贝的实现方式
ES6展开运算符 …
1 | var person = {
|
2 | name: '张三',
|
3 | age: 20,
|
4 | list: [1, 2, 3],
|
5 | say:function(){console.log('hello');},
|
6 | check:new RegExp("e")
|
7 | }
|
8 | var user = { ...person}
|
9 | user.name = '李四'
|
10 | console.log(user.name);
|
11 | console.log(person.name);
|
Object.assign()
1 | var person = {
|
2 | name: '张三',
|
3 | age: 20,
|
4 | list: [1, 2, 3]
|
5 | }
|
6 | var user = Object.assign({},person)
|
7 | console.log(user);
|
lodash clone
1 | var objects = [{ 'a': 1 }, { 'b': 2 }];
|
2 | var shallow = _.clone(objects);
|
3 | console.log(shallow[0] === objects[0]);
|
4 |
|
Array concat
Array 的 concat方法不改变原数组,返回一个浅复制原数组的元素的新数组。如果元素是引用类型,就会拷贝这个引用的内存地址到新数组内。两个元素引用地址共享,所以如果发生改变将影响另外一个。如果元素是基本类型的话就会遵循浅拷贝的机制
1 | var array = [1,[2,3,4],[5,6],{name:'张三'}]
|
2 |
|
3 | let array_concat = array.concat()
|
4 | console.log(array_concat);
|
5 | array_concat[1][0] = 'apple'
|
6 | console.log(array_concat[1]);
|
7 | console.log(array[1]);
|
8 | array_concat[2] = ['apple','mac','xiaomi']
|
9 | console.log(array_concat[2]);
|
10 | console.log(array[2]);
|
11 | array_concat[3].name = '王五';
|
12 | console.log(array_concat[3].name);
|
13 | console.log(array[3].name);
|
遍历复制
1 | function shallowCopy(object) {
|
2 | let temp = {};
|
3 | for (const key in object) {
|
4 | if (Object.hasOwnProperty.call(object, key)) {
|
5 | temp[key] = object[key];
|
6 | }
|
7 | }
|
8 | return temp;
|
9 | }
|
深拷贝的实现方式
JSON.parse/JSON.stringify
可以满足基本的使用,但是对于正则表达式类型、函数类型等无法进行深拷贝。
1 | var person = {
|
2 | name: '张三',
|
3 | age: 20,
|
4 | list: [1, 2, 3],
|
5 | say:function(){console.log('hello');},
|
6 | check:new RegExp("e")
|
7 | }
|
8 | var user = JSON.parse(JSON.stringify(person));
|
9 | user.name = '李四';
|
10 | console.log(user.name);
|
11 | console.log(person.name);
|
12 | user.list[0] = 'apple'
|
13 | console.log(user.list);
|
14 | console.log(person.list);
|
15 | console.log(user.say);
|
16 | console.log(user.check);
|
lodash cloneDeep
1 | var objects = [{ 'a': 1 }, { 'b': 2 }];
|
2 | var deep = _.cloneDeep(objects);
|
3 | console.log(deep[0] === objects[0]);
|
4 |
|
递归遍历
1 | var person = {
|
2 | name: '张三',
|
3 | age: 20,
|
4 | list: [1, 2, 3],
|
5 | say: function () { console.log('hello'); },
|
6 | check: new RegExp("e")
|
7 | }
|
8 |
|
9 |
|
10 | function cloneDeep(object, hash = new WeakMap()) {
|
11 | if (!isObject(object)) return object;
|
12 | if(object instanceof Date) return new Date(object)
|
13 | if(object instanceof RegExp) return new RegExp(object)
|
14 | if (hash.has(object)) return hash.get(object)
|
15 | let target = Array.isArray(object) ? [] : {};
|
16 | hash.set(object, target);
|
17 | for (const key in object) {
|
18 | if (Object.hasOwnProperty.call(object, key)) {
|
19 | if (typeof object[key] === 'object') {
|
20 | target[key] = cloneDeep(object[key], hash)
|
21 | } else {
|
22 | target[key] = object[key];
|
23 | }
|
24 | }
|
25 | }
|
26 | return target;
|
27 | }
|
28 |
|
29 | function isObject(object) {
|
30 | return typeof object === 'object' && object != null;
|
31 | }
|
32 |
|
33 | var user = cloneDeep(person);
|
34 | user.name = '李四';
|
35 | console.log(user.name);
|
36 | console.log(person.name);
|
37 | user.list[0] = 'apple'
|
38 | console.log(user.list);
|
39 | console.log(person.list);
|
40 | console.log(user.say);
|
41 | console.log(user.check);
|