javascript如何实现深拷贝和浅拷贝

187 阅读3分钟

javascript中的对象是引用类型,将一个对象赋值给另外一个变量时,变量的指针指向的还是对象本身,无论定义多少个变量去引用对象所有指针都会指向同一个对象,这样在实际的应用中就会出现一个问题:

let obj = {
	name: 'li'
}
let a= obj;
let b=obj;
a.name='jie'
console.log(b.name);
//输出结果为'jie'

明明改变的是变量a的属性,变量b也被影响了,为了解决这个问题,我们只能去复制一个新的对象

浅拷贝

创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

浅拷贝只能复制一层,如果这个对象下的某个属性引用的是对象,那么它的属性还是会受改引用的对象影响

Object.assign()

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象

let obj = {
	name: 'li'
}
let a= obj;
let b=Object.assign({},obj);
a.name='jie'
console.log(b.name);
//输出结果为'li'

Array.prototype.slice()

slice() 方法返回一个新的数组对象,这一对象是一个由 begin和 end(不包括end)决定的原数组的浅拷贝。原始数组不会被改变。

let arr = [1,2,3,4,5,6,7,8,9];
let b = arr.slice(1);
console.log(b);
// [2, 3, 4, 5, 6, 7, 8, 9]

arr[1] = 10;
console.log(arr);
// [1,10, 3, 4, 5, 6, 7, 8, 9]

console.log(b);
// [2, 3, 4, 5, 6, 7, 8, 9]

展开运算符...

展开运算符是一个 es6 / es2015特性,它提供了一种非常方便的方式来执行浅拷贝,这与 Object.assign ()的功能相同。

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


### 深拷贝
显然,浅拷贝很难满足我们的需求,特别是在项目中,一个对象或数组很有肯能是多位数组和对象
#### JSON.parse(JSON.stringify(object))
通过将对象转json字符串,再将字符串转json对象,可以实现深拷贝
```js
  let a ={
      b:{
          name:'li'
      }
  }
  let newa = JSON.parse(JSON.stringify(a))
  a.b.name = 'jie';
  console.log(newa.b.name)
//li

该方法够处理JSON格式能表示的所有数据类型,但是无法拷贝对象里面的函数正则表达式等,而且会丧失所有的constructor,也就是说,将是破坏整条prototype链。

递归浅拷贝

我们来写一个深拷贝的方法

function deepClone(obj){
    if(typeof obj !== 'object' || obj === null){
        return obj;
    }
    // 初始化返回结果
    let result;
    if(obj instanceof Array){
        result = [];
    }else {
        result = {};
    }
    for(let key in obj){
        // 判断是不是对象本身的属性
        if(obj.hasOwnProperty(key)){
            result[key] = deepClone(obj[key]);
        }
    }
    return result;

}

深拷贝方法已经创建好,下面来测试一下

let a ={
    a:1,
    b:[1,2,3,4],
    c:{
        name:123123
    }
};
let b= deepClone(a);
a.a=2;
console.log(b.a); //1

没有问题。