深拷贝 浅拷贝 赋值

206 阅读2分钟

数据类型

在开始了解浅拷贝与深拷贝之前,让我们先来回顾一下 JavaScript 的数据类型。

1.基本数据类型(number、string、boolean、undefined、null)

  • 基本数据类型的值是按值访问的,基本类型的值是不可变的
  • 基本数据类型的比较是值比较

2.引用类型(object)

  • 引用类型的值是按引用访问的,引用类型的值是动态可变的
  • 引用类型的比较是引用地址的比较

浅拷贝

浅拷贝:创建一个新对象,复制基本类型的数据和引用类型的地址(子对象),引用类型的地址对应的内容修改会相互影响;

浅拷贝的通用方法

function shallowCopy(obj){
            if(typeof obj!=='object'){
                return ;
            }
            var newObj=obj instanceof Array?[]:{};
            for(var key in obj){
                if(obj.hasOwnProperty(key)){//剔除原型上的属性
                    newObj[key]=obj[key];
                }
            }
            return newObj;
        }
        var obj = [1, 2, 3, 4, {a: 1}, {b: { c: 2 }} ];
        var newObj = copy(obj);
        obj[0]=6;
        newObj[4] = 6;
        newObj[5].b.c = 6;
        console.log(obj);// [6, 2, 3, 4, {a: 6}, {b: { c: 6 }} ]
        console.log(newObj);// [1, 2, 3, 4, 6, {b: { c: 6 }} ]

实现数组浅拷贝的方法([...arr],slice,concat)

let arr=[];
let [...newArr]=arr;
或newArr=arr.slice(0);
或newArr=[].concat(arr);

实现对象浅拷贝的方法

let obj={a:1,b:2,c:[3,4]};
let {...newObj}=obj;
或 let newObject=Object.assign({},obj)

Object.assign({},obj)只复制顶层对象类型的属性。

深拷贝

深拷贝:创建一个新对象,复制基本类型的数据和引用类型数据地址对应的内容,修改新对象,不会影响原对象的数据。

实现深拷贝的方法:

1.递归

 function copy(obj) {
        if (!obj || typeof obj !== 'object') {
            return
        }
        var newObj = Array.isArray(obj) ? [] : {};
        for (var key in obj) {
            if (typeof obj[key] === 'object' && obj[key]) {
                newObj[key] = copy(obj[key])
            } else {
                newObj[key] = obj[key]
            }
            <!--newObj[key]=typeof obj[key]==='object'?copy(obj[key]):obj[key]-->
        }
        return newObj;
    }
var obj = { a: 1, b: { c: 2 } };
var newObj = copy(obj);
newObj.a = 6;
newObj.b.c = 6;
console.log(obj);//{ a: 1, b: { c: 2 } }
console.log(newObj);{ a: 6, b: { c: 6 } }

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

var obj = { a: 1, b: { c: 2 } };
var newObj = JSON.parse(JSON.stringify(obj));
console.log(obj);//{ a: 1, b: { c: 2 } }
console.log(newObj);//{ a: 6, b: { c: 6 } }

弊端:

因为在序列化JavaScript对象时,所有函数和原型成员会被有意忽略。

通俗点说,JSON.parse(JSON.stringfy(X)),其中X只能是Number, String, Boolean, Array, 扁平对象,即那些能够被 JSON 直接表示的数据结构。

赋值、浅拷贝、深拷贝的区别