版本1
const b = JSON.parse(JSON.stringify(b))
缺点:
- 不支持函数
- 不支持循环引用
- 不支持正则表达式
- 不支持
new Date() - 不支持
Symbol() - 不支持
undefined
版本二
克隆
- 函数
- 日期
- 正则
- 普通对象
- 数组
克隆函数
function cloneFn(fn) {
if (fn.prototype) {
return function () {
return fn.call(this, ...arguments);
};
} else {
return (...args) => fn.call(undefined, ...args);
}
}
克隆日期
const a = new Date(1997)
console.log(a - 0); // 1997
const b = new Date(a - 0);
克隆正则
const a = /hi/
const b = new RegExp(a.source, a.flags);
克隆object
export function isObject(value) {
return typeof value === 'object' && value !== null;
}
export function deepClone(data) {
if (isObject(data)===false) return data;
let res = {};
for (let key in data) {
res[key] = deepClone(data[key]);
}
return res;
}
克隆数组
export function isFunction(value) {
return typeof value === 'function';
}
export function deepClone(data) {
if (isFunction(data) === false) return data;
let res = []
for (let key in data) {
res[key] = deepClone(data[key]);
}
return res;
}
不克隆继承来的属性
const person = {
name: 'Bob',
age: 30
};
// 继承属性
person.__proto__.country = 'USA';
for (const key in person) {
if (person.hasOwnProperty(key)) {
console.log(key); // 只输出: 'name', 'age'
}
}
export function isObject(value) {
return typeof value === 'object' && value !== null;
}
export function deepClone(data) {
if (isObject(data)===false) return data;
let res = {};
for (let key in data) {
if (data.hasOwnProperty(key)) res[key] = deepClone(data[key]);
}
return res;
}
ES6代替方案
// Object.keys() 只返回自身属性
Object.keys(obj).includes('name'); // true
// Object.getOwnPropertyNames()
Object.getOwnPropertyNames(obj).includes('name'); // true
// Reflect.ownKeys()(包含Symbol)
Reflect.ownKeys(obj).includes('name'); // true
解决无限循环
export function isObject(value) {
return typeof value === 'object' && value !== null;
}
export function deepClone(data, hash = new Map()) {
if (isObject(data) === false) return data;
if (hash.get(data)) return hash.get(data);
let res = {};
hash.set(data, res);
for (let key in data) {
res[key] = deepClone(data[key], hash)
}
return res;
}
封装
export function isObject(value) {
return typeof value === 'object' && value !== null;
}
function cloneFn(fn) {
if (fn.prototype) {
return function () {
return fn.call(this, ...arguments);
};
}
return (...args) => fn.call(undefined, ...args);
}
export function deepClone(data, hash = new Map()) {
if (isObject(data) === false) return data;
if (hash.get(data)) return hash.get(data);
let res = {};
if (data instanceof Array) res = [];
if (data instanceof Date) res = new Date(data - 0);
if (data instanceof RegExp) res = new RegExp(data.source, data.flags);
if (data instanceof Function) res = cloneFn(data);
hash.set(data, res);
for (let key in data) {
if (data.hasOwnProperty(key)) res[key] = deepClone(data[key], hash); // 不克隆继承来的属性
}
return res;
}
版本三
克隆
- 普通对象
- 数组
- Map
- Set
function deepClone(data: any, hash = new WeakMap()) {
if (!isObject(data)) {
return data;
}
if (hash.has(data)) {
return hash.get(data);
}
let res: any = {};
hash.set(data, res);
if (data instanceof Array) {
res = data.map((item) => deepClone(item, hash));
}
if (data instanceof Map) {
res = new Map();
data.forEach((v, k) => {
const v1 = deepClone(v, hash);
const k1 = deepClone(k, hash);
res.set(k1, v1);
});
}
if (data instanceof Set) {
res = new Set();
data.forEach((item) => {
const item1 = deepClone(item, hash);
res.add(item1);
});
}
Object.keys(data).forEach((key) => {
res[key] = deepClone(data[key], hash);
});
return res;
}
function isObject(data: any) {
if (data === null) return false;
if (typeof data === "object") return true;
return false;
}
测试
值类型
console.log(deepClone(100));
console.log(deepClone("abc"));
console.log(deepClone(null));
普通对象和数组
const obj = {
name: "jack",
info: {
city: "北京",
},
arr: [1, 2, 3],
};
const obj2 = deepClone(obj);
obj.info.city = "上海";
console.log(obj.info.city, obj2.info.city); // 上海, 北京
obj.arr.push(5);
console.log(obj.arr, obj2.arr); // [1,2,3,5] [1,2,3]
Map
const m1 = new Map();
m1.set("x", 10);
m1.set("y", 20);
const m2 = deepClone(m1);
console.log(m2.size); // 2
const obj1 = {
map: m1,
};
const obj2 = deepClone(obj1);
console.log(obj2.map.size); // 2
Set
const set1 = new Set([1, 2, 3]);
const set2 = deepClone(set1);
console.log(set2.size); // 3
const obj1 = {
set: set1,
};
const obj2 = deepClone(obj1);
console.log(obj2.set.size); // 3
循环引用
const a: any = {};
a.self = a;
const b = deepClone(a);
console.log(b.self === b, b.seft === a); // true, false