深拷贝和深拷贝(谈一谈深拷贝和浅拷贝)
浅拷贝是指,一个新的对象对原始对象的属性值进行精确地拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值,如果是引用数据类型,拷贝的就是内存地址,我来为大家讲解一下关于深拷贝和深拷贝?跟着小编一起来看一看吧!
深拷贝和深拷贝
1. 浅拷贝浅拷贝是指,一个新的对象对原始对象的属性值进行精确地拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值,如果是引用数据类型,拷贝的就是内存地址。
如果其中一个对象的引用内存地址发生改变,另一个对象也会发生变化。
浅拷贝的方法(1)直接赋值
let arr1 = [1,2,3];
let arr2 = arr1;
new2[0] = 0;
console.log(arr1); // [0, 2, 3]
console.log(arr1); // [0, 2, 3]
console.log(arr1 === arr2); // true
Object.assign()是ES6中对象的拷贝方法,接受的第一个参数是目标对象,其余参数是源对象,用法:Object.assign(target, source_1, ···),该方法可以实现浅拷贝,也可以实现一维对象的深拷贝。 ** 注意:
- 如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的属性会覆盖前面的属性。
- 如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转为对象然后返回。
- 因为null 和 undefined 不能转化为对象,所以第一个参数不能为null或 undefined,会报错。
let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3);
console.log(target); // {a: 1, b: 2, c: 3}
// 俗称合并对象
使用扩展运算符可以在构造字面量对象的时候,进行属性的拷贝。语法:let cloneObj = { ...obj };
let obj1 = {a:1,b:{c:1}}
let obj2 = {...obj1};
obj1.a = 2;
console.log(obj1); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
obj1.b.c = 2;
console.log(obj1); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}}
- slice()方法是JavaScript数组的一个方法,这个方法可以从已有数组中返回选定的元素:用法:array.slice(start, end),该方法不会改变原始数组。
- 该方法有两个参数,两个参数都可选,如果两个参数都不写,就可以实现一个数组的浅拷贝。
let arr = [1,2,3,4];
console.log(arr.slice()); // [1,2,3,4]
console.log(arr.slice() === arr); //false
- concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
- 该方法有两个参数,两个参数都可选,如果两个参数都不写,就可以实现一个数组的浅拷贝。
let arr = [1,2,3,4];
console.log(arr.concat()); // [1,2,3,4]
console.log(arr.concat() === arr); //false
复制代码
// 浅拷贝的实现;
function shallowCopy(object) {
// 只拷贝对象
if (!object || typeof object !== "object") return;
// 根据 object 的类型判断是新建一个数组还是对象
let newObject = Array.isArray(object) ? [] : {};
// 遍历 object,并且判断是 object 的属性才拷贝
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] = object[key];
}
}
return newObject;
}
深拷贝是指,对于简单数据类型直接拷贝他的值,对于引用数据类型,在堆内存中开辟一块内存用于存放复制的对象,并把原有的对象类型数据拷贝过来,这两个对象相互独立,属于两个不同的内存地址,修改其中一个,另一个不会发生改变。
(1)Object.assign()Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
let obj1 = { person: {name: "kobe", age: 41},sports:'basketball' };
let obj2 = Object.assign({}, obj1);
obj2.person.name = "wade";
obj2.sports = 'football'
console.log(obj1); // { person: { name: 'wade', age: 41 }, sports: 'basketball' }
- JSON.parse(JSON.stringify(obj))是目前比较常用的深拷贝方法之一,它的原理就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象。
- 这个方法可以简单粗暴的实现深拷贝,但是还存在问题,拷贝的对象中如果有函数,undefined,symbol,当使用过JSON.stringify()进行处理之后,都会消失。
let obj1 = { a: 0,
b: {
c: 0
}
};
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.a = 1;
obj1.b.c = 1;
console.log(obj1); // {a: 1, b: {c: 1}}
console.log(obj2); // {a: 0, b: {c: 0}}
该函数库也有提供_.cloneDeep用来做 Deep Copy
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
function clone(source) {
//判断source是不是对象
if (source instanceof Object == false) return source;
//判断source是对象还是数组
let target = Array.isArray(source) ? [] : {};
for (var i in source) {
if (source.hasOwnProperty(i)) {
//判断数据i的类型
if (typeof source[i] === 'object') {
target[i] = clone(source[i]);
} else {
target[i] = source[i];
}
}
}
return target;
}
console.log(clone({b: {c: {d: 1}}})); // {b: {c: {d: 1}}})
总结:实际开发中可以使用手写的深拷贝函数,进行封装,然后需要深拷贝的时候去调用封装好的函数;用得少的话,或者只是处理简单数据逻辑处理,使用JSON.parse(JSON.stringify(obj))完全是可以的。
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com