JS中浅拷贝和深拷贝的几种实现方式
概念
深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象。它们最根本的区别在于是否真正获取了一个对象的复制实体,而不是引用。简单来说,假设B复制了A,当修改B时,看A是否会发生变化,如果A变了,说明是浅拷贝;如果A没变,那就是深拷贝
浅拷贝
1. 用 = 号赋值引用地址
let obj = {
name: '李四',
age: 20,
sex: '男',
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
colleges: "野鸡烧烤工程系"
grade: 2020
name: '野鸡大学'
stuNo: 2020123456
},
say: () => {
console.log('哇塞')
}
};
let obj2 = obj;
obj2.name = 'Rose';
obj2.sex = '女';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
2. for…in
被循环的对象存在嵌套对象时为浅拷贝
let obj = {
name: '李四',
age: 20,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
};
let obj2 = { };
for (let key in obj) {
obj2[key] = obj[key];
}
obj2.name = '小六';
obj2.sex = '男';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
3. Object.assign()
① Object.assign()只有源对象,没有目标对象时为浅拷贝
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
};
let obj2 = Object.assign(obj);
obj2.name = 'Rose';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
② Object.assign() 是一种可以对非嵌套对象进行深拷贝的方法,如果对象中出现嵌套情况,那么其对被嵌套对象的行为就成了普通的浅拷贝
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
};
let obj2 = {
name: '小二',
school: {
name: '凤凰大学'
}
};
Object.assign(obj2, obj);
obj2.name = '小六';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
深拷贝
1. JSON.parse(JSON.stringify())
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
};
let obj2 = JSON.parse(JSON.stringify(obj));
obj2.name = '小六';
obj2.school.name = '野鸡变凤凰';
console.log(obj);
console.log(obj2);
注意:这种方式无法拷贝 正则表达式,undefine,function
2. for…in
被循环的对象不存在嵌套对象时为深拷贝
let obj = {
name: '李四',
age: 20,
sex: '男',
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
say: () => {
console.log('哇塞')
}
};
let obj2 = { };
for (let key in obj) {
obj2[key] = obj[key];
}
obj2.name = 'Rose';
obj2.sex = '女';
console.log('obj', obj);
console.log('obj2', obj2);
3. Object.assign()
Object.assign() 方法只复制源对象中可枚举的属性和对象自身的属性。如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
say: () => {
console.log('哇塞')
}
};
let obj2 = {
name: '小二',
};
Object.assign(obj2, obj);
obj2.name = '小六';
console.log('obj', obj);
console.log('obj2', obj2);
4. 递归
递归拷贝所有层级属性
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
}
function deepClone(obj) {
let objClone = Array.isArray(obj) ? [] : { };
if(obj && typeof obj === 'object' ) {
for(key in obj) {
if(obj.hasOwnProperty(key)){
// 判断 obj 子元素是否为对象,如果是则递归复制
if(obj[key] && typeof obj[key] === 'object') {
objClone[key] = deepClone(obj[key]);
} else {
// 如果不是则直接复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let obj2 = deepClone(obj);
obj2.name = 'Rose';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
5. $.extend()
通过 jQuery 的 extend() 方法实现深拷贝,第一个参数 true 为深拷贝,false 为浅拷贝
let obj = {
name: '李四',
age: 20,
sex: null,
tel: /^1[345789]\d{9}$/,
address: undefined,
flag: true,
school: {
name: '野鸡大学',
grade: 2020,
stuNo: 2020123456,
colleges: '野鸡烧烤工程系',
},
say: () => {
console.log('哇塞')
}
}
var obj2 = $.extend(true, { }, obj); // true 为深拷贝,false 为浅拷贝
obj2.name = 'Rose';
obj2.school.name = '野鸡变凤凰';
console.log('obj', obj);
console.log('obj2', obj2);
6. slice()
slice() 对数组进行深拷贝
let arr = [1, 2, 3, 4, 5, 6];
let arr2 = arr.slice(0);
arr2[0] = 'Rose';
arr2[1] = '女';
console.log('arr', arr); // [1, 2, 3, 4, 5, 6]
console.log('arr2', arr2); // ["Rose", "女", 3, 4, 5, 6]
7. concat()
concat() 对数组进行深拷贝
let arr = [1, 2, 3, 4, 5, 6];
let arr2 = arr.concat();
arr2[0] = 'Rose';
arr2[1] = '女';
console.log('arr', arr); // [1, 2, 3, 4, 5, 6]
console.log('arr2', arr2); // ["Rose", "女", 3, 4, 5, 6]
还没有评论,来说两句吧...