深浅拷贝
pr1mavera 2019/11/21
手写代码
js基础
# 浅拷贝
# 通过解构实现
const shallowCloneByDeconst = obj => ({ ...obj });
# 通过Object.assign实现
const shallowCloneByObjectAssign = obj => Object.assign({}, obj);
# 数组还可通过以下两种方式实现
// 1. Array.prototype.concat()
const shallowCloneByConcat = arr => arr.concat();
// 2. Array.prototype.slice()
const shallowCloneBySlice = arr => arr.slice();
# 深拷贝
# 通过json实现
- 缺陷
- 不能处理函数,会被转换成null
- 只能处理普通对象
const deepCloneByJson = obj => JSON.parse(JSON.stringify(obj));
# 通过递归实现
- 思路
- 递归查看对象中的可枚举属性,若是基本类型则赋值,若是引用类型则递归
- 使用
WeakMap
处理环 - 使用结构化方式分别处理不同类型的对象
- 缺陷 - 不能处理固有对象及宿主对象
// 获取构造函数类型
const getCtorType = tar => Object.prototype.toString.call(tar).slice(8, -1);
// 判断是否是引用类型
const isObject = target => target && (typeof target == 'object' || typeof target == 'function');
// 拷贝函数
const cloneFunction = func => {
const bodyReg = /(?<={)(.|\n)+(?=})/m;
const paramReg = /(?<=\().+(?=\)\s+{)/;
const funcString = func.toString();
if (func.prototype) {
const param = paramReg.exec(funcString);
const body = bodyReg.exec(funcString);
if (body) {
if (param) {
const paramArr = param[0].split(',');
return new Function(...paramArr, body[0]);
} else {
return new Function(body[0]);
}
} else {
return null;
}
} else {
return eval(funcString);
}
}
/**
* 递归深拷贝
* @param {any} obj 待拷贝对象
* @param {WeakMap | undefined} dict 处理循环引用所使用的字典
*/
const deepClone = (obj, dict = new WeakMap()) => {
// 处理基本类型
if (!isObject(obj)) return obj;
// 处理环
if (dict.has(obj)) return dict.get(obj);
let newObj;
let type = getCtorType(obj);
switch (type) {
case 'Number':
newObj = new Number(obj.valueOf());
break;
case 'String':
newObj = new String(obj.toString());
break;
case 'Boolean':
newObj = new Boolean(obj.valueOf());
break;
case 'Date':
newObj = new Date(obj.getTime());
break;
case 'Function':
newObj = cloneFunction(obj);
break;
case 'Symbol':
newObj = Object(Symbol.prototype.valueOf.call(newObj));
break;
case 'RegExp':
newObj = new RegExp(obj.source /* 匹配表达式 */, /\w*$/.exec(obj) /* 匹配模式 */);
// 重置上次匹配后的位置记录
newObj.lastIndex = obj.lastIndex;
break;
case 'Error':
newObj = new Error(obj.toString().slice(7, -1));
break;
default:
newObj = new obj.constructor(obj);
break;
}
for (const key in obj) {
newObj[key] = isObject(obj[key])
? deepClone(obj[key])
: obj[key];
}
dict.set(obj, newObj);
return newObj;
};
← call & apply curry →