js中的浅拷贝和深拷贝

118 阅读3分钟

原始对象数据

var obj = {
        id: 1,
        name: 'zs',
        info:{
                sex : "female"
        },
	color: ["red","pink","yellow"]
}

要拷贝到的新对象

var o = {}

浅拷贝

浅拷贝只拷贝一层,对象值完全复制,深层次只是拷贝引用,并且会影响原始对象值(有些数组方法是不改变原始值)

1. 循环赋值


for(var k in obj){
  //      console.log(k);              //id name info
  //      console.log(obj[k])         //1 zs
        o[k] = obj[k]
  //      console.log(o[k]);           //1 zs
}
console.log(o);                    //{id: 1, name: 'zs', info: {sex:'female'}, color: Array(3)}
-------修改新对象里的性别值,发现原始对象和新对象值都变了-----------
console.log(o);       //color: (3) ['red', 'pink', 'yellow']  id: 1   info: {sex: 'male'}  name: "zs"
o.info.sex = "male"
console.log(obj);     //color: (3) ['red', 'pink', 'yellow']  id: 1   info: {sex: 'male'}  name: "zs"

2. Object.assign() 语法糖

Object.assign(o,obj)       //第一个参数是要拷贝到的数组,第二个是拷贝的对象
console.log(o);           //{id: 1, name: 'zs', info: {sex: 'female'}, color: Array(3)}
-------修改新对象里的性别值,发现原始对象和新对象值都变了-----------
console.log(o);       //color: (3) ['red', 'pink', 'yellow']  id: 1   info: {sex: 'male'}  name: "zs"
o.info.sex = "male"
console.log(obj);     //color: (3) ['red', 'pink', 'yellow']  id: 1   info: {sex: 'male'}  name: "zs"

3. concat() 适用数组

var oldArr =  [0,1,2,[3,4]]
var newArr = oldArr.concat()
console.log(...oldArr);     // 0 1 2  [3, 4]    原始值不改变
newArr[1] = 0
console.log(...newArr)     //0 0 2 [3, 4]        还是继续引用深层次数组

4. slice() 适用数组

var oldArr =  [0,1,2,[3,4]]
var newArr = oldArr.slice(0)
console.log(...oldArr);     // 0 1 2  [3, 4]    原始值不改变
newArr[1] = 0
console.log(...newArr)      //0 0 2 [3, 4]        还是继续引用深层次数组

5. Array.from() 适用数组

var oldArr =  [0,1,2,[3,4]]
var newArr = Array.from(oldArr)
console.log(...oldArr);     // 0 1 2  [3, 4]    原始值不改变
newArr[1] = 0
console.log(...newArr)      //0 0 2 [3, 4]        还是继续引用深层次数组

6. ...扩展运算符 适用数组

var oldArr =  [0,1,2,[3,4]]
var newArr = [...oldArr]
console.log(...oldArr);     // 0 1 2  [3, 4]    原始值不改变
newArr[1] = 0
console.log(...newArr)      //0 0 2 [3, 4]        还是继续引用深层次数组

深拷贝

深拷贝全部复制,不会影响原始对象值

1. 封装函数

但是这个方法值为undefined拷贝会把原始值也会成undefined

function DeepClone(newObj,oldObj){
    for(var k in oldObj){
        var item = oldObj[k];                  //获取属性值
//	console.log(item);                    //1 zs {sex: 'female'} ["red","pink","yellow"]
        if(item instanceof Array){            //先判断属性值是否数组,先判断Object,数组属于Object,会跳过后续判断数组的条件
                newObj[k] = []                    //将旧数组属性值(["red","pink","yellow"])给新数组的属性(newObj[k],相当于obj.color,它必须是一个数组接收)
                DeepClone(newObj[k],item)         //递归,把属性值给新数组属性
        }else if(item instanceof Object){     //判断属性值是否对象
                newObj[k] = {}                     //将旧对象属性值({sex: 'female'})给新数组的属性(newObj[k],相当于obj.info,它必须是一个对象接收)
                DeepClone(newObj[k],item)
        }else{
                newObj[k] = item 
        }
    }
}
DeepClone(o,obj)
-------修改新对象里的性别值,发现原始对象没变,新对象变了-----------
console.log(o);  //color: (3) ['red', 'pink', 'yellow']  id: 1   info: {sex: 'male'}  name: "zs"
o.info.sex = "male"
console.log(obj); //color: (3) ['red', 'pink', 'yellow']  id: 1   info: {sex: 'female'}  name: "zs"

2. JSON.parse(JSON.stringify())

var o = JSON.parse(JSON.stringify(obj))
-------修改新对象里的性别值,发现原始对象没变,新对象变了-----------
console.log(o);  //color: (3) ['red', 'pink', 'yellow']  id: 1   info: {sex: 'male'}  name: "zs"
o.info.sex = "male"
console.log(obj); //color: (3) ['red', 'pink', 'yellow']  id: 1   info: {sex: 'female'}  name: "zs"

缺点:这个方法值为undefined拷贝会跳过,并且原始值也会变,函数和symbol则会跳过

var obj = {
           name: 'A',
           name1: undefined,
           name3: function() {},
           name4:  Symbol('A')
}
var o = JSON.parse(JSON.stringify(obj))
console.log(o);  //{name: 'A'}
o.name = "male"
console.log(obj); //{name: 'A', name1: undefined, name4: Symbol(A), name3: ƒ}