基本类型和引用类型的拷贝
JavaScript 的数据类型有两种:
在对这两种类型进行拷贝时,表现有所不同
浅拷贝和深拷贝的区别
深拷贝和浅拷贝都是针对的引用类型
浅拷贝的实现
最简单的浅拷贝只需要进行赋值就可以,相当于为原对象添加了一个引用;这种情况下,原对象的每个改变都会影响复制后的对象
1 2 3 4 5 6 7 8
| let arr = [1, 2, 3, { key: 'val' }]; let target = arr; console.log(target);
arr[1] = 'a'; arr[3].key = 'anotherVal'; console.log(target); console.log(arr === target);
|
可以对原对象进行更“深”一层的浅拷贝,也即是对象第一层的引用分离,而更深层的引用保持不变
1 2 3 4 5 6 7 8 9 10 11 12 13
| function shallowCopy(source) { if (typeof source === 'object') { let target = (source instanceof Array) ? [] : {}; for (let key in source) { if (source.hasOwnProperty(key)) { target[key] = source[key]; } } return target; } else { return source; } }
|
1 2 3 4 5 6 7 8 9
| let arr = [1, 2, 3, { key: 'val' }]; let target = shallowCopy(arr); console.log(target); console.log(arr === target);
arr[1] = 'a'; arr[3].key = 'anotherVal'; console.log(target); console.log(arr);
|
深拷贝的实现
递归
可以通过递归复制对象所有层级的属性
1 2 3 4 5 6 7 8 9 10 11
| function deepCopy(source) { if (typeof source === 'object') { let target = (source instanceof Array) ? [] : {}; for (let key in source) { target[key] = deepCopy(source[key]); } return target; } else { return source; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let person = { name: { first_name: 'Albert', family_name: 'Einstein' }, job: 'scientist' }
let clonePerson = deepCopy(person); person.name.first_name = 'Mike'; console.log(person);
console.log(clonePerson);
|
循环
使用递归存在一个问题,当被复制对象层级很深时会栈溢出,可以改用循环来实现深拷贝
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 40 41 42
| function deepCopy(source) { if (typeof source !== 'object') return source;
let target = (source instanceof Array) ? [] : {}; let loopList = [ { parent: target, key: undefined, data: source } ];
while (loopList.length) { let node = loopList.pop(), parent = node.parent, key = node.key, data = node.data;
let res = parent; if (typeof key !== 'undefined') { res = parent[key] = {}; } for (let k in data) { if (data.hasOwnProperty(k)) { if (typeof data[k] === 'object') { loopList.push({ parent: res, key: k, data: data[k] }); } else { res[k] = data[k]; } } } }
return target; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let person = { name: { first_name: 'Albert', family_name: 'Einstein' }, job: 'scientist' }
let clonePerson = deepCopy(person); person.name.first_name = 'Mike'; console.log(person);
console.log(clonePerson);
|
使用 JSON 的 API
1 2 3
| function deepCopy(source) { return JSON.parse(JSON.stringify(source)); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let person = { name: { first_name: 'Albert', family_name: 'Einstein' }, job: 'scientist' }
let clonePerson = deepCopy(person); person.name.first_name = 'Mike'; console.log(person);
console.log(clonePerson);
|