前置知识
- 对象类型在赋值的过程中其实是复制了地址,从而会导致改变了一方其他也都被改变的情况
let a = {
age: 1
}
let b = a
a.age = 2
console.log(b.age)
浅拷贝
- Object.assign : 拷贝所有的属性值到新的对象中,如果属性值是对象的话,拷贝的是地址,所以并不是深拷贝
let a = {
age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age)
let a = {
age: 1
}
let b = {...a}
a.age = 2
console.log(b.age)
深拷贝
- JSON.parse(JSON.stringify(object))
- 会忽略 undefined
- 会忽略 symbol
- 不能序列化函数
- 不能解决循环引用的对象,会报错抛出异常
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first)
let a = {
age: undefined,
sex: Symbol('male'),
jobs: function() {},
name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b)
function isObject(obj) {
return typeof obj === 'object' && obj != null
}
function cloneDeep1(obj){
if(!isObject(obj)) return obj
var newObj = Array.isArray(obj)? [] : {}
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = isObject(obj[key])? cloneDeep1(obj[key]) : obj[key]
}
}
return newObj
}
- 问题:递归方法最大的问题在于爆栈,当数据的层次很深是就会栈溢出,例如循环引用
var a = {
name: "muyiy",
a1: undefined,
a2: null,
a3: 123,
book: {title: "You Don't Know JS", price: "45"}
}
a.circleRef = a
JSON.parse(JSON.stringify(a))
cloneDeep1(a)
- 解决方法:循环检测(设置一个数组或者哈希表存储已拷贝过的对象,当检测到当前对象已存在于哈希表中时,取出该值并返回即可)
function cloneDeep3(source, hash = new WeakMap()) {
if (!isObject(source)) return source;
if (hash.has(source)) return hash.get(source);
var target = Array.isArray(source) ? [] : {};
hash.set(source, target);
for(var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (isObject(source[key])) {
target[key] = cloneDeep3(source[key], hash);
} else {
target[key] = source[key];
}
}
}
return target;
}
function cloneDeep3(source, uniqueList) {
if (!isObject(source)) return source;
if (!uniqueList) uniqueList = [];
var target = Array.isArray(source) ? [] : {};
var uniqueData = find(uniqueList, source);
if (uniqueData) {
return uniqueData.target;
};
uniqueList.push({
source: source,
target: target
});
for(var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (isObject(source[key])) {
target[key] = cloneDeep3(source[key], uniqueList);
} else {
target[key] = source[key];
}
}
}
return target;
}
function find(arr, item) {
for(var i = 0; i < arr.length; i++) {
if (arr[i].source === item) {
return arr[i];
}
}
return null;
}