深拷贝
浅拷贝只是创建了一个新的对象,复制了原有对象的基本类型的值,而引用数据类型只拷贝了一层属性,再深层的还是无法进行拷贝。深拷贝则不同,对于复杂引用数据类型,其在堆内存中完全开辟了一块内存地址,并将原有的对象完全复制过来存放。
深拷贝后的对象与原始对象是相互独立、不受影响的,彻底实现了内存上的分离。
var obj = {
a: function () { console.log('hello world最强写手') },
b: { c: 5 },
c: [0, 1, 2],
d: 'jack',
e: new Date(),
f: null,
g: undefined
}
var clone = function (obj) {
return JSON.parse(JSON.stringify(obj));
}
var b = clone(obj);
console.log(b);
上述clone的方法会忽略function和undefined的字段. 而且只能克隆原始对象自身的值,不能克隆它继承的值.
JSON.parse(JSON.stringify())使用时要注意的点:
-
如果obj里面有时间对象,则
JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象;var test = { name: 'a', date: [new Date(1656390281537), new Date(1656390297387)], }; let b; let c; c = JSON.parse(JSON.stringify(test)); console.log(c); console.log(typeof c.date[0]); //string -
如果obj里有
RegExp、Error对象,则序列化的结果将只得到空对象;const test = { name: 'a', date: new RegExp('\w+'), }; const copyed = JSON.parse(JSON.stringify(test)); test.name = 'test1' console.error('test', test, copyed) -
如果obj里有函数,
undefined,则序列化的结果会把函数或 undefined丢失;var test = { a: function () { console.log('hello world最强写手') }, b: { c: 5 }, c: [0, 1, 2], d: 'jack', e: new Date(), f: null, g: undefined, h: obj } var clone = function (obj) { return JSON.parse(JSON.stringify(obj)); } var b = clone(obj); console.log(b); -
如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null.
var obj = { a: function () { console.log('hello world最强写手') }, b: { c: 5 }, c: [0, 1, 2], d: 'jack', e: new Date(), f: null, g: NaN, h: obj } var clone = function (obj) { return JSON.parse(JSON.stringify(obj)); } var b = clone(obj); console.log(b); -
JSON.stringify()只能序列化对象的可枚举的自有属性。//不可枚举是遍历不出来。 -
如果对象中存在循环引用的情况也无法正确实现深拷贝。
常规版的深拷贝:
不能解决,正则,date,对象的循环引用的问题。
```
const deepClone = (target, map = new Map()) => {
if (typeof target === 'object' && target !== null) {
if(map.has(target)){
return map.get(target);
}
const cloneTarget = Array.isArray(target) ? [] : {};
map.set(target,cloneTarget);
if(Array.isArray(target)){
target.forEach((item,index)=>{
cloneTarget[index] = deepClone(item,map);
})
}else{
Object.keys(target).forEach((key)=>{
cloneTarget[key] = deepClone(target[key],map);
})
}
return cloneTarget;
} else {
return target;
}
}
```
开发版的深拷贝
function forEach(array, iteratee) {
let index = -1;
const length = array.length;
while (++index < length) {
iteratee(array[index], index);
}
return array;
}
function isObject(target) {
const type = typeof target;
return target !== null && (type === 'object' || type === 'function');
}
function getType(target) {
return Object.prototype.toString.call(target);
}
const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const objectTag = '[object Object]';
const boolTag = '[object Boolean]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const numberTag = '[object Number]';
const regexpTag = '[object RegExp]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const deepTag = [mapTag, setTag, arrayTag, objectTag]
function getInit(target) {
const Ctor = target.constructor;
return new Ctor();
}
function clone(target, map = new WeakMap()) {
// 克隆原始类型
if (!isObject(target)) {
return target;
}
// 初始化
const type = getType(target);
let cloneTarget;
if (deepTag.includes(type)) {
cloneTarget = getInit(target, type);;
}
// 防止循环引用
if (map.get(target)) {
return map.get(target);
}
map.set(target, cloneTarget);
// 克隆set
if (type === setTag) {
target.forEach(value => {
cloneTarget.add(clone(value, map));
});
return cloneTarget;
}
// 克隆map
if (type === mapTag) {
target.forEach((value, key) => {
cloneTarget.set(key, clone(value, map));
});
return cloneTarget;
}
// 克隆对象和数组
const keys = type === arrayTag ? undefined : Object.keys(target);
forEach(keys || target, (value, key) => {
if (keys) {
key = value;
}
cloneTarget[key] = clone(target[key], map);
});
return cloneTarget;
}
克隆Symbol
function cloneSymbol(targe) {
return Object(Symbol.prototype.valueOf.call(targe));
}