浅拷贝
数组浅拷贝 Array.prototype.concat()
// concat() 方法用于连接两个或多个数组。
// 该方法不会改变现有的数组,而是返回一个新的数组
constnewArr=arr.concat()
数组浅拷贝 Array.prototype.slice()
// slice() 方法可从已有的数组中返回选定的元素
// 注意: slice() 方法不会改变原始数组,而是返回一个新的数组
constnewArr=arr.slice()
对象浅拷贝 Object.assign()
// Object.assign() 方法可以将任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象
constnewObj=Object.assign({}, obj)
扩展运算符 ...
// 数组
constnewArr= [...arr];
// 对象
constnewObj= [...obj];
for in 浅拷贝
const_shallowClone=target=> {
// 基本数据类型直接返回
if (typeoftarget==='object'&&target!==null) {
// 获取target的构造体
constconstructor=target.constructor
// 构造体为以下类型直接返回
if (/^(Function|RegExp|Date|Map|Set)$/i.test(constructor.name)) returntarget
// 判断是否是一个数组
constcloneTarget=Array.isArray(target) ? [] : {}
for (constkeyintarget) {
// 只拷贝其自身的属性
if (target.hasOwnProperty(key)) {
cloneTarget[key] =target[key]
}
}
returncloneTarget
} else {
returntarget
}
}
深拷贝
JSON.parse(JSON.stringify(obj))
不能拷贝函数和undefined, 日期,正则
constnewData=JSON.parse(JSON.stringify(data))
递归深拷贝
/**
* 深拷贝简化版
* @param {any} target
* @param {WeakMap} map
* @returns {any} cloneTarget
*/
const_completeDeepClone= (target, map=newWeakMap()) => {
// 基本数据类型,直接返回
if (typeoftarget!=='object'||target===null) returntarget
// 函数 正则 日期 ES6新对象,执行构造题,返回新的对象
constconstructor=target.constructor
if (/^(Function|RegExp|Date|Map|Set)$/i.test(constructor.name)) returnnewconstructor(target)
// map标记每一个出现过的属性,避免循环引用
if (map.get(target)) returnmap.get(target)
map.set(target, true)
constcloneTarget=Array.isArray(target) ? [] : {}
for (propintarget) {
if (target.hasOwnProperty(prop)) {
cloneTarget[prop] =_completeDeepClone(target[prop], map)
}
}
returncloneTarget
}
/**
* 深拷贝加强版
* @param {any} parent
* @returns {any} child
*/
exportconstclone=parent=> {
// 判断类型
constisType= (obj, type) => {
if (typeofobj!=="object") returnfalse;
consttypeString=Object.prototype.toString.call(obj);
letflag;
switch (type) {
case"Array":
flag=typeString==="[object Array]";
break;
case"Date":
flag=typeString==="[object Date]";
break;
case"RegExp":
flag=typeString==="[object RegExp]";
break;
case"Set":
flag=typeString==="[object Set]";
break;
case"Map":
flag=typeString==="[object Map]";
break;
default:
flag=false;
}
returnflag;
};
// 处理正则
constgetRegExp=re=> {
varflags="";
if (re.global) flags+="g";
if (re.ignoreCase) flags+="i";
if (re.multiline) flags+="m";
returnflags;
};
// 维护储存循环引用的对象
constcached=newWeakMap;
const_clone=parent=> {
if (parent===null) returnnull;
if (typeofparent!=="object") returnparent;
// 循环引用则直接返回
if (cached.get(parent)) returncached.get(parent)
letchild, proto;
if (isType(parent, "Array")) {
// 对数组做特殊处理
child= [];
} elseif (isType(parent, "RegExp")) {
// 对正则对象做特殊处理
child=newRegExp(parent.source, getRegExp(parent));
if (parent.lastIndex) child.lastIndex=parent.lastIndex;
} elseif (isType(parent, "Date")) {
// 对Date对象做特殊处理
child=newDate(parent.getTime());
} elseif (isType(parent, "Set")) {
// 对Set对象做特殊处理
child=newSet();
parent.forEach(val=> {
child.add(_clone(val))
})
} elseif (isType(parent, "Map")) {
// 对Map对象做特殊处理
child=newMap();
parent.forEach((val, key) => {
child.set(key, _clone(val))
})
} else {
// 处理对象原型
proto=Object.getPrototypeOf(parent);
// 利用Object.create切断原型链
child=Object.create(proto);
}
cached.set(parent, child)
for (letiinparent) {
// 递归
child[i] =_clone(parent[i]);
}
returnchild;
};
return_clone(parent);
};