分身术种类
- 普通分身术:有其形,无其实,不具有完备的主体
- 影分身术:从真身上得到完备的继承,具有和真身一样的完备性
普通分身术
普通分身术技术实现
/**
* 简单克隆实现
*/
const originObj = {
a: 1,
b: 2
};
const simpleCloneObj = JSON.parse(JSON.stringify(originObj));
普通分身术局限性
- 无法实现对函数、RegExp等特殊对象的克隆
- 会抛弃对象的constructor,所有的构造函数会指向Object
- 对象有循环引用的话会报错
影分身术
影分身术技术实现
/**
* 深度克隆实现
*/
const deepClone = parent => {
// 判断类型
const isType = (obj, type) => {
if (typeof obj !== 'object') {
return false;
}
const typeString = Object.prototype.toString.call(obj);
let flag;
switch (type) {
case 'Array':
flag = typeString === '[object Array]';
break;
case 'Date':
flag = typeString === '[object Date]';
break;
case 'RegExp':
flag = typeString === '[object RegExp]';
break;
}
return flag;
};
// 处理正则
const getRegExp = reg => {
let flags = '';
if (reg.global) {
flags += 'g';
}
if (reg.ignoreCase) {
flag += 'i';
}
if (reg.mutiline) {
flag += 'm';
}
return flags;
};
// 维护两个储存循环引用的数组
const parents = [];
const children = [];
const _clone = parent => {
if (parent === null) {
return null;
}
if (typeof parent !== 'object') {
return parent;
}
let child, proto;
if (isType(parent, 'Array')) {
// 对数组做特殊处理
child = [];
} else if (isType(parent, 'RegExp')) {
// 对正则对象做特殊处理
child = new RegExp(parent.source, getRegExp(parent));
if (parent.lastIndex) {
child.lastIndex = parent.lastIndex;
}
} else if (isType(parent, 'Date')) {
child = new Date(parent.getTime());
} else {
// 处理对象原型
proto = Object.getPrototypeOf(parent);
// 利用Object.create切断原型链
child = Object.create(proto);
}
// 处理循环引用
const index = parents.indexOf(parent);
if (index != -1) {
// 如果父数组存在本对象,说明之前已经被引用过,直接返回此对象
return children[index];
}
parents.push(parent);
children.push(child);
for (let i in parent) {
// 递归
child[i] = _clone(parent[i]);
}
return child;
};
return _clone(parent);
};
const originObj = {
a: 1,
b: {
aa: 11,
bb: 22
},
c () {
console.log('I am a function');
},
d: [1, 2, 3, 4]
};
const shadowObj = deepClone(originObj);
console.log(shadowObj);
影分身术进一步优化
- 增加对Buffer、Promise、Set、Map等特殊对象的处理
- 对于确保没有循环引用对象的,可以省去对循环引用的特殊处理,因为这很消耗时间
参考资料
-
https://www.cxymsg.com/guide/jsWritten.html#%E5%AE%9E%E7%8E%B0%E8%8A%82%E6%B5%81%E5%87%BD%E6%95%B0%EF%BC%88throttle%EF%BC%89
延伸阅读