写在前面
使用场景
在我们日常开发当中,我们经常会遇到深拷贝的场景,比如使用Vue技术栈的时候,我们需要把this.updateInfo中的数据传递给接口,而若干数据类型又不是我们预期想要的,这个时候怎么办呢?
使用深拷贝的方式,把this.updateInfo的数据拷贝一份,从而不影响原来的数据。
使用递归的方式
function deepCopy (obj) {
var result = Array.isArray(obj) ? [] : {};
for(var key in obj){
if(obj.hasOwnProperty(key)){
if(typeof obj[key] === 'object' && obj[key]){
result[key] = deepCopy(obj[key])
}else{
result[key] = obj[key]
}
}
}
return result
}
使用JSON.parse(JSON.stringify())的方式
function deepCopy (obj){
return JSON.parse(JSON.stringify(obj))
}
var obj2 = {a: 2, b: 2}
var copyObj = deepCopy(obj2)
console.log(obj2);
console.log(copyObj);
// 方法缺点, 当值为undefined、function、symbol 会在转换过程中被忽略
使用slice的方式
let arr = [1,2,3,4]
let arr1 = arr.slice()
使用ES6 扩展运算符的方式
let arr = [1,2,3,4]
let [a,b,c,d] = [...arr]
使用Object.assign()的方式
let obj = {
a: 1,
b: 2,
}
let copyObj = Object.assign({},obj)
copyObj.a = 3;
obj.a // 1
copyObj.a // 3
使用jQuery的方式
var arr = [1,2,3,4]
var newArr = $.extend(true,[],arr) //true则为深拷贝 false为浅拷贝
进阶版
const isComplexDataType = obj => (typeof obj === 'object' || typeof obj === 'function') && (obj !== null)
const deepClone = function (obj, hash = new WeakMap()) {
if (obj.constructor === Date)
return new Date(obj) // 日期对象直接返回一个新的日期对象
if (obj.constructor === RegExp)
return new RegExp(obj) //正则对象直接返回一个新的正则对象
//如果循环引用了就用 weakMap 来解决
if (hash.has(obj)) return hash.get(obj)
let allDesc = Object.getOwnPropertyDescriptors(obj)
//遍历传入参数所有键的特性
let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
//继承原型链
hash.set(obj, cloneObj)
for (let key of Reflect.ownKeys(obj)) {
cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key], hash) : obj[key]
}
return cloneObj
}
let obj = {
num: 0,
str: '',
boolean: true,
unf: undefined,
nul: null,
obj: { name: '我是一个对象', id: 1 },
arr: [0, 1, 2],
func: function () { console.log('我是一个函数') },
date: new Date(0),
reg: new RegExp('/我是一个正则/ig'),
[Symbol('1')]: 1,
};
Object.defineProperty(obj, 'innumerable', {
enumerable: false, value: '不可枚举属性'
}
);
obj = Object.create(obj, Object.getOwnPropertyDescriptors(obj))
obj.loop = obj // 设置loop成循环引用的属性
let cloneObj = deepClone(obj)
cloneObj.arr.push(4)
console.log('obj', obj)
console.log('cloneObj', cloneObj)