浅拷贝
浅拷贝只能拷贝顶层属性基本数据类型, 也就是如果父对象的属性是一个对象或数组, 那么子对象获取到的只是一个内存地址而不是一个真正的对象, 所以一旦修改父对象也会跟着被篡改.
1 | function shallowCopy ( parent ) { |
深拷贝
深拷贝也就是能够实现数组和对象拷贝, 深拷贝与浅拷贝对比, 深拷贝会在堆区开辟新的一块来储存新的对象. 两个对象对应的是两个不同的内存地址, 所以修改其中一个对象的属性并不会影响到另一个对象的属性. 实现深拷贝也有两种方式: 一种是递归/ 一种是JSON.
递归
1
2
3
4
5
6
7
8
9
10function deepCopy (parent, child = {}) {
for (let i in parent) {
if (typeof parent[i] === 'object') {
child[i] = (parent[i].constructor == Array) ? [] : {};
deepCopy(parent[i], child[i])
} else {
child[i] = parent[i]
}
}
}JSON解析(严格的 JSON 格式)
1
2
3
4
5
6
7
8
9
10
11
12
13var o = {
age: '18',
friends: ['老张', '老王'],
job: {
main: '睡觉',
sub: '躺着'
}
};
var result = JSON.parse( JSON.stringify(o));
result.name = 'cara';
result.friends.push('老李');
console.dir(o);
console.dir(result)
以上两种方式无法解析一下几种情况:
- RegExp 对象
- 函数
- 会摒弃对象的 constructor , 所有构造函数都会指向 Object
- 对象循环引用也会报错
所以要面对不同的对象, 做不同的处理方式, 就需要检查一下对象的类型:
1 | // 检查类型 |
👇测试一波:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39// 测试
function person(name) {
this.name = name;
}
const Cara = new person('Cara');
function say() {
console.log('hello world!');
}
const oldObj = {
a: say,
c: new RegExp('ab+c', 'i'),
d: Cara,
};
oldObj.b = oldObj;
const newObj = clone(oldObj)
console.log(newObj.a, oldObj.a)
// [Function: say] [Function: say]
console.log(newObj.b, oldObj.b)
// {
// a: [Function: say],
// c: /ab+c/i,
// d: person { name: 'Messi' },
// b: [Circular]
// }
// {
// a: [Function: say],
// c: /ab+c/i,
// d: person { name: 'Messi' },
// b: [Circular]
// }
console.log(newObj.c, oldObj.c)
// /ab+c/i /ab+c/i
console.log(newObj.d.constructor, oldObj.d.constructor)
// [Function: person][Function: person]
目前我们上面说的几种坑就得以解决, 不过这还不是最完整的方案, 还有一些 ES6 里面的对象也需要我们做特殊的处理, 不过现在这个版本在日常还是够用了. 另外在生产环境中还是建议用 lodash
的 _.cloneDeep
Created on 2017-8-15 by cara