影分身术——JS深克隆
分身术种类
- 普通分身术:有其形,无其实,不具有完备的主体
- 影分身术:从真身上得到完备的继承,具有和真身一样的完备性
普通分身术
普通分身术技术实现
/** * 简单克隆实现 */ 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等特殊对象的处理
- 对于确保没有循环引用对象的,可以省去对循环引用的特殊处理,因为这很消耗时间
参考资料
微信公众号“前端那些事儿”