深复制
下列代码实现的是第二种方式,递归复制:
js
import deepCopy from './deep-copy'
const obj = {
// =========== 1.基础数据类型 ===========
num: 0, // number
str: '', // string
bool: true, // boolean
unf: undefined, // undefined
nul: null, // null
sym: Symbol('sym'), // symbol
bign: BigInt(1n), // bigint
// =========== 2.Object类型 ===========
// 普通对象
obj: {
name: '我是一个对象',
id: 1,
},
// 数组
arr: [0, 1, 2],
// 函数
func: function () {
console.log('我是一个函数');
},
// 日期
date: new Date(0),
// 正则
reg: new RegExp('/我是一个正则/ig'),
// Map
map: new Map().set('mapKey', 1),
// Set
set: new Set().add('set'),
// =========== 3.其他 ===========
[Symbol('1')]: 1, // Symbol作为key
};
console.log(obj);
console.log(deepCopy(obj));
js
// 浅拷贝与深拷贝:
// 基本数据储存在栈中,引用类型数据储存在堆之中
// 基本类型数据可直接复制,引用类型数据在赋值时,新变量没有获得新值,而是将指针指向此对象的堆位置
// 浅拷贝:拷贝了对象的引用地址,没有获得新值;深拷贝:获得新值,而不是获得引用地址
// 浅拷贝:let a = b;let a = Object.assign({},b)
// 深拷贝:let a = JSON.parse(JSON.stringify(b));
// 考虑多种引用类型的完整深拷贝:
import { isPlainObject, getObjectType, objectType } from "../modules/type";
/**
* @method deepCopy
* @description 深拷贝
* @param {Object} obj 需要拷贝的对象
* @return {Object} 返回复制的对象
* @example
* const newObject = deepCopy(oldObject)
*/
export const deepCopy = function (origin, map = new WeakMap()) {
// 一、无数据 或者 类型为基本类型、函数则直接返回
if (!origin || !isPlainObject(origin)) {
return origin;
}
// 二、获取引用数据类型
const type = getObjectType(origin);
// 三、已经存在,则直接返回,循环引用
if (map.has(origin)) {
return map.get(origin);
}
// 四、根据类型处理
// 1,正则或者Date类型
if (type === objectType.reg || type === objectType.date) {
const newObject = new origin.constructor(origin.valueOf());
map.set(newObject);
return newObject;
}
// 2,Set 类型
if (type === objectType.set) {
const newObject = new Set();
for (const value of origin) {
newObject.add(deepCopy(value, map));
}
map.set(newObject);
return newObject;
}
// 3,Map类型
if (type === objectType.map) {
const newObject = new Map();
for (const [key, value] of origin) {
newObject.set(key, deepCopy(value, map));
}
map.set(newObject);
return newObject;
}
// 4,Array 或者 Object 类型
// 考虑了以Symbol作为key的情况
const keys = Reflect.ownKeys(origin);
// 获取描述符
const descriptors = Object.getOwnPropertyDescriptors(origin);
// 考虑原型链,继承原对象的原型,描述符
const newObject = Object.create(Object.getPrototypeOf(origin), descriptors);
map.set(newObject);
keys.forEach((key) => {
const value = origin[key];
newObject[key] = deepCopy(value, map);
});
// 数组类型则还原
return type === objectType.array ? Array.from(newObject) : newObject;
};
js
/** @module Type */
/**
* @constant {Object} objectType 常用的引用类型
* @property {String} objectType.object 常规对象
* @property {String} objectType.array 数组
* @property {String} objectType.date 日期
* @property {String} objectType.reg 正则
* @property {String} objectType.set Set
* @property {String} objectType.map Map
*/
export const objectType = {
object: "[object Object]",
array: "[object Array]",
date: "[object Date]",
reg: "[object RegExp]",
set: "[object Set]",
map: "[object Map]",
};
/**
* @description 获取对象引用类型,可以和 objectType 包含的类型进行比较
* @method getObjectType
* @param {Object} obj
* @return {String}
* @example
* if(getObjectType(obj)===objectType.array){
*
* }
*/
export function getObjectType(obj) {
return Object.prototype.toString.call(obj);
}
/**
* @method isNumber
* @description 判断传入值是否是数值
* @param {any} val
* @return {Boolean}
*/
export function isNumber(val) {
return typeof val === "number";
}
/**
* @method isUndefined
* @description 判断传入值是否是未定义
* @param {any} val
* @return {Boolean}
*/
export function isUndefined(val) {
return typeof val === "undefined";
}
/**
* @method isPlainObject
* @description 是否为普通对象
* @param {any} val
* @return {Boolean}
*/
export function isPlainObject(val) {
return val && val.constructor.name === "Object";
}