毫无破绽的前端深拷贝方法

141 阅读1分钟

一次性定义完前端所有类型的深拷贝方法,然后直接调用一个方法就完事了,深拷贝在日常开发中是有很多应用场景的,他也是非常重要的,写一个合格的深拷贝方法是很有必要的。那怎么才能写一个合格的深拷贝方法呢?或者说,怎么才能写一个毫无破绽的深拷贝方法

定义全局常量

// 自定义全局方法
// 可遍历的类型
const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const objectTag = '[object Object]';
// 不可遍历类型
const symbolTag = '[object Symbol]';
const regexpTag = '[object RegExp]';
const funcTag = '[object Function]';
// 将可遍历类型存在一个数组里
const canForArr = ['[object Map]', '[object Set]', '[object Array]', '[object Object]'];
// 将不可遍历类型存在一个数组
const noForArr = ['[object Symbol]', '[object RegExp]', '[object Function]'];

方法

  // 拷贝Function的方法
  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);
  	}
  },
  // 拷贝Symbol的方法
  cloneSymbol(targe) {
  	return Object(Symbol.prototype.valueOf.call(targe));
  },
  // 拷贝RegExp的方法
  cloneReg(targe) {
  	const reFlags = /\w*$/;
  	const result = new targe.constructor(targe.source, reFlags.exec(targe));
  	result.lastIndex = targe.lastIndex;
  	return result;
  },
  // 判断类型的函数
  checkType(target) {
  	return Object.prototype.toString.call(target);
  },
  // 判断引用类型的temp
  checkTemp(target) {
  	const c = target.constructor;
  	return new c();
  },
  // 调用深拷贝方法
  deepClone(target, map = new Map()) {
  	// 获取类型
  	const type = this.checkType(target);
  	// 基本数据类型直接返回
  	if (!canForArr.concat(noForArr).includes(type)) return target;
  	// 判断Function,RegExp,Symbol
  	if (type === funcTag) return this.cloneFunction(target);
  	if (type === regexpTag) return this.cloneReg(target);
  	if (type === symbolTag) return this.cloneSymbol(target);
  	// 引用数据类型特殊处理
  	const temp = this.checkTemp(target);
  	if (map.get(target)) {
  		// 已存在则直接返回
  		return map.get(target);
  	}
  	// 不存在则第一次设置
  	map.set(target, temp);
  	// 处理Map类型
  	if (type === mapTag) {
  		target.forEach((value, key) => {
  			temp.set(key, this.deepClone(value, map));
  		});
  		return temp;
  	}
  	// 处理Set类型
  	if (type === setTag) {
  		target.forEach(value => {
  			temp.add(this.deepClone(value, map));
  		});
  		return temp;
  	}
  	// 处理数据和对象
  	for (const key in target) {
  		// 递归
  		temp[key] = this.deepClone(target[key], map);
  	}
  	return temp;
  }

使用方法

const a = {
    name: 'sunshine_lin',
    age: 23,
    hobbies: { sports: '篮球', tv: '雍正王朝' },
    works: ['2020', '2021'],
    map: new Map([['haha', 111], ['xixi', 222]]),
    set: new Set([1, 2, 3]),
    func: (name, age) => `${name}今年${age}岁啦!!!`,
    sym: Symbol(123),
    reg: new RegExp(/haha/g),
}
const b = deepClone(a)
console.log(b)

作者:Sunshine_Lin 链接:juejin.cn/post/702279…