深拷贝和深拷贝(谈一谈深拷贝和浅拷贝)

浅拷贝是指,一个新的对象对原始对象的属性值进行精确地拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值,如果是引用数据类型,拷贝的就是内存地址,我来为大家讲解一下关于深拷贝和深拷贝?跟着小编一起来看一看吧!

深拷贝和深拷贝(谈一谈深拷贝和浅拷贝)

深拷贝和深拷贝

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

(2)Object.assign()

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} // 俗称合并对象

(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}}

(4)数组方法实现数组浅拷贝1)Array.prototype.slice
  • 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

2)Array.prototype.concat
  • concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
  • 该方法有两个参数,两个参数都可选,如果两个参数都不写,就可以实现一个数组的浅拷贝。

let arr = [1,2,3,4]; console.log(arr.concat()); // [1,2,3,4] console.log(arr.concat() === arr); //false 复制代码

(5)手写实现浅拷贝

// 浅拷贝的实现; 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; }

2. 深拷贝

深拷贝是指,对于简单数据类型直接拷贝他的值,对于引用数据类型,在堆内存中开辟一块内存用于存放复制的对象,并把原有的对象类型数据拷贝过来,这两个对象相互独立,属于两个不同的内存地址,修改其中一个,另一个不会发生改变。

(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' }

(2)JSON.stringify()
  • 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}}

(3)函数库lodash的_.cloneDeep方法

该函数库也有提供_.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

(4)手写实现深拷贝函数

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

    分享
    投诉
    首页