浅拷贝和深拷贝

74 阅读3分钟

浅拷贝

1. Object.assign(target, source) 将多个源对象中的属性复制到一个目标对象中

//例如1:
let obj1 = {
  person:{
    name: 'kobe', age:18
  },
  sports: 'basketball'
}

let obj2 = Object.assign({}, obj1)
obj2.person.name = 'wade'
obj2.sports = 'football'
console.log(obj1)// { person:{ name: 'wade', age:18 }, sports: 'football'}

//例如2
const source1 = {
  a: 123,
  b: 123
}
const source2 = {
  b: 789,
  d: 789
}
const target = {
  b: 456,
  c: 456
}
// 参数1:将属性复制到的目标对象;参数2:复制的源对象
// 将source1中的属性和值 复制(覆盖)到target中, 有重复到会被覆盖源对象覆盖
// const res1 = Object.assign(target, source1)
// console.log(res1)//{b: 123, c: 456, a: 123}
// console.log(res1 === target) //true

const res2 = Object.assign(target, source1, source2)
console.log(res2)//{b: 789, c: 456, a: 123, d: 789}
console.log(res2 === target) //true

2.展开运算符 …

let obj1 = {
  name: 'kobe',
  address:{ x:100 }
}

let obj2 = {...obj1}
obj1.name = 'wade'
obj1.address.x = 200
console.log(obj2)// { name: 'wade', address:{ x:200 } }

3.数组concat() 方法

let arr = [1,3, { name: 'kobe'}]
let arr2 = arr.concat()
arr2[2].name = 'wade'
console.log(arr,arr2)//[1,3, { name: 'wade'}]

4.数组slice() 方法

let arr = [1,3, { name: 'kobe'}]
let arr2 = arr.slice()
arr2[2].name = 'wade'
console.log(arr2)//[1,3, { name: 'wade'}]

深拷贝

1.JSON.parse(JSON.stringify(obj))

满足一般使用场景,但无法实现对象中方法(fountion)的深拷贝

let obj = {
	id: 1,
	name: '张三',
	age: 10,        
}
let newObj = JSON.parse(JSON.stringify(obj))

(1)如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式,而不是对象的形式

(2)如果obj里有RegExp(正则表达式的缩写)、Error对象,则序列化的结果将只得到空对象;

(3)如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失

(4)如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null

(5)JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor

(6)如果对象中存在循环引用的情况也无法正确实现深拷贝

2.递归拷贝

递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。

比较全面的深拷贝,缺点是较为繁琐

function deepClone(obj) {
    var target = {};
    for(var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            if (typeof obj[key] === 'object') {
                target[key] = deepClone(obj[key]); 
            } else {
                target[key] = obj[key];
            }
        }
    }
    return target;
}

3.jQuery的extend方法实现深拷贝

jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象。

第一个参数是boolean类型,表示深浅拷贝,true表示深拷贝,false表示浅拷贝。只有两个参数,那么就把jQuery作为target,把第二个参数的字段赋给target,然后返回target。多于两个参数,把第二个参数作为target,然后把后面的参数的字段赋给target,最后面返回target.

var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝
let obj = {
        a:1,
        b: {
            c:2
        }
    }
    let copyObj = {}
    $.extend(true,copyObj, obj);
    copyObj.b = 3
    console.log(obj, copyObj)

问题:当然如果两拷贝对象中有相同的属性名时,后者的值也会覆盖前者的值,就像这样:

let obj = {
        a:1,
        b: {
            c:2
        }
    }
    let obj2 = {
        a:2,
        d:4
    }

    $.extend(true,obj, obj2);
    console.log(obj, obj2)

jQuery这个框架现在使用量比较小,个人不做深入研究了

4.Object.assign(obj1, obj2)---伪

只有一级属性为深拷贝,二级属性后就是浅拷贝

let obj = {
	id: 1,
	name: '张三',
	age: 10,        
}
let newObj = Object.assign({}, obj)

5.扩展运算符---伪

只有一级属性为深拷贝,二级属性后就是浅拷贝

var obj = {
        a: 1,
        b: 2
      }
 
var obj1 = {...obj}

6.数组使用数组方法进行深拷贝(concat、slice)---伪

只有一级属性为深拷贝,二级属性后就是浅拷贝,如数组中的对象

 var arr1 = [1, 2, 3, 4]
 var arr2 = arr1.concat()
 var arr3 = arr1.slice(1)