1.数组拷贝
1.浅拷贝(新数组改变还会对原数组影响)
Array.slice()与Array.concat()
var source = [1, null, undefined, {name: 'anjou', age: undefined, sex: null}, [2, 3, 4], function() {}]
var target = source.slice() || source.concat()
target[0] = 5
target[3].name = '====';
target[4][0] = 6
console.log(source) // [1, null, undefined, {name: '====', age: undefined, sex: null}, [6, 3, 4], ƒ ()]
console.log(target) // [5, null, undefined, {name: '====', age: undefined, sex: null}, [6, 3, 4], ƒ ()]
es6 扩展运算符
var source = [1, null, undefined, {name: 'anjou', age: undefined, sex: null}, [2, 3, 4], function() {}]
var target = [...source]
target[0] = 5
target[3].name = 'anpoly';
target[4][0] = 6
console.log(source) // [1, null, undefined, {name: 'anpoly', age: undefined, sex: null}, [6, 3, 4], ƒ ()]
console.log(target) // [5, null, undefined, {name: 'anpoly', age: undefined, sex: null}, [6, 3, 4], ƒ ()]
es6 Object.assign()
var source = [1, null, undefined, {name: 'anjou', age: undefined, sex: null}, [2, 3, 4], function() {}]
var proto = Object.getPrototypeOf(source)
var target = Object.assign({}, Object.create(proto), source)
target[0] = 5
target[3].name = 'anpoly'
target[4][0] = 6
console.log(source) // [1, null, undefined, {name: 'anpoly', age: undefined, sex: null}, [6, 3, 4], ƒ ()]
console.log(target) // [5, null, undefined, {name: 'anpoly', age: undefined, sex: null}, [6, 3, 4], ƒ ()]
2.深拷贝(彻底切断了数组内引用类型的引用关系)
JSON.parse()与 JSON.stringify()
var source = [1, null, undefined, {name: 'anjou', age: undefined, sex: null}, [2, 3, 4], function() {}]
var target = JSON.parse(JSON.stringify(source))
target['0'] = 5
target['3'].name = 'anpoly'
target['4'][0] = 8
console.log(source) // [1, null, undefined, {name: 'anjou', age: undefined, sex: null}, [2, 3, 4], ƒ ()]
console.log(target) // [5, null, null, {name: 'anpoly', sex: null}, [6, 3, 4], null]
我们发现使用JSON.parse与JSON.stringify可以实现数组的深拷贝。但是我们发现拷贝后的数组与我们预想的结果有很大差别,这是因为JSON.stringify(…) 在对象中遇到 undefined 、 function 和 symbol 时会自动将其忽略, 在 数组中则会返回 null (以保证单元位置不变)
2.对象拷贝
1.浅拷贝
es6 Object.assign()
var source2 = {0:1, 1:null, 2:undefined, 3:{name: 'anjou', age: undefined, sex: null}, 4:[2, 3, 4], 5: function() {}}
var obj = Object.getPrototypeOf(source2)
var target = Object.assign({}, Object.create(obj), source2)
target['0'] = 5
target['3'].name = 'anpoly'
target['4'][0] = 6
console.log(source2) // {0: 1, 1: null, 2: undefined, 3: {name: "anpoly", age: undefined, sex: null}, 4: [6, 3, 4], 5:ƒ ()}
console.log(target) // {0: 5, 1: null, 2: undefined, 3: {name: "anpoly", age: undefined, sex: null}, 4: [6, 3, 4], 5:ƒ ()}
2.深拷贝
var source2 = {0:1, 1:null, 2:undefined, 3:{name: 'anjou', age: undefined, sex: null}, 4:[2, 3, 4], 5: function() {}}
var target = JSON.parse(JSON.stringify(source2))
target['0'] = 5
target['3'].name = 'anpoly'
target['4'][0] = 6
console.log(source2) // {0: 1, 1: null, 2: undefined, 3: {name: "anjou", age: undefined, sex: null}, 4: [2, 3, 4], 5:ƒ ()}
console.log(target) // {0: 1, 1: null, 3: {name: "anpoly", sex: null}, 4: [6, 3, 4]}
通过上面的这些拷贝技巧的分析,我们发现没有一个可以做到比较完整的深拷贝。那要如何实现一个数组或者一个对象的深拷贝呢? 接下来我们将写一个简单的克隆函数来实现数组与对象的深拷贝。
// 克隆函数
var source = [1, null, undefined, {name: 'anjou', age: undefined, sex: null}, [2, 3, 4], function() {}]
function deepCopy(data) {
if (typeof data !== 'object' || data == null) return data
var newData = data instanceof Array ? [] : {}
for (var key in data) {
newData[key] = typeof data[key] === 'object' ? (data[key] === null ? null : deepCopy(data[key])) : data[key]
}
return newData
}
var target = deepCopy(source)
target[0] = 5
target[3].name = 'anpoly'
target[4][0] = 6
console.log(source) // [1, null, undefined, {name: 'anjou', age: undefined, sex: null}, [2, 3, 4], ƒ ()]
console.log(target) // [5, null, undefined, {name: 'anpoly', age: undefined, sex: null}, [6, 3, 4], ƒ ()]