您的位置:

深浅拷贝在JavaScript中的应用

一、浅拷贝和深拷贝的区别

在深入探讨深浅拷贝之前,需要先了解它们的区别。

浅拷贝和深拷贝是指对一个对象进行拷贝后,新对象和原对象各自独立存在,互不影响。

浅拷贝只是拷贝了原对象的基本数据类型(包括String、Number、Boolean、undefined、null),而对于对象、数组等引用数据类型,只是拷贝了它们的地址,新旧对象共享同一个引用类型数据。

深拷贝则是将原对象上所有的属性以及其对应的引用类型数据(包括引用类型数据的属性)全部拷贝到新对象中,新旧对象互不影响。

二、浅拷贝的实现方式

JavaScript中很容易实现浅拷贝,可以使用ES6中的拓展运算符(...)或Object.assign()方法进行实现。

以下是使用拓展运算符实现浅拷贝的代码:

let obj = {a: 1, b: 2, c: {d: 3}};
let newObj = {...obj};
console.log(newObj); // {a: 1, b: 2, c: {d: 3}}

以下是使用Object.assign()方法实现浅拷贝的代码:

let obj = {a: 1, b: 2, c: {d: 3}};
let newObj = Object.assign({}, obj);
console.log(newObj); // {a: 1, b: 2, c: {d: 3}}

这样实现的浅拷贝只拷贝了原对象的第一层属性,对于对象的属性值如果还是对象则只是拷贝了地址,故新旧对象的第二层及以下的属性值仍是引用类型数据,会造成新旧对象共享。

三、深拷贝的实现方式

相对于浅拷贝,深拷贝会将原对象上所有属性以及属性值进行递归拷贝,生成与原对象完全独立的新对象。

不过,JavaScript中实现深拷贝并不是一件简单的事情,因为对象的属性值如果还是对象,要实现完全独立的拷贝需要进行递归拷贝,而循环引用、计算量过大等问题也会导致深拷贝的实现困难,而且性能也是有影响的。

以下是实现深拷贝常用的方式:

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

JSON.parse()和JSON.stringify()两个方法是JavaScript内置的方法,可以将JavaScript对象转化为JSON格式的字符串,也可以将JSON格式的字符串转化回JavaScript对象。

因为JSON格式的字符串是一个字符类型的数据,所以对JSON格式字符串的处理更加简单,使用JSON.parse()和JSON.stringify()可以实现深拷贝。

以下是实现深拷贝的示例代码:

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

需要注意的是,JSON.stringify()方法在将JavaScript对象转化为JSON格式字符串时会忽略掉函数、正则表达式、以及undefined类型值,所以在运用该方式进行深拷贝的时候,需要注意是否需要将这些类型值拷贝下来。

同时,该方式也是存在局限性的,对于循环引用的对象无法进行深拷贝,会直接报错。

2. 递归实现深拷贝

另一种实现深拷贝的方式是使用递归,遍历原对象的所有属性和属性值,如果属性值是对象,则递归调用拷贝函数,直至所有属性和属性值都被完全拷贝。

以下是使用递归实现深拷贝的示例代码:

function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  let newObj = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      newObj[key] = deepClone(obj[key]);
    }
  }
  return newObj;
}

let obj = {a: 1, b: 2, c: {d: 3}};
let newObj = deepClone(obj);
console.log(newObj); // {a: 1, b: 2, c: {d: 3}}

这种方式实现比较直接,但是需要注意两点,一是需要判断属性值是否为对象,否则递归调用时会报错;二是需要使用hasOwnProperty()方法判断遍历的属性是否为对象自身的属性,避免将原型上的属性拷贝到新对象上。

四、深浅拷贝的应用场景

浅拷贝和深拷贝都有其应用场景:

浅拷贝适用于那些不需要完全独立的对象拷贝,比如单个对象的属性值不是引用类型的数据,在对该对象进行拷贝时可以使用浅拷贝,以减少运算量和内存占用,提升程序执行效率。

而深拷贝适用于那些需要完全独立对象拷贝的场景,比如避免代码中对象的相互影响、避免模拟深度拷贝时递归调用深度过大......

五、总结

浅拷贝和深拷贝是两种用于对象拷贝的方式,浅拷贝只是将原对象的基本数据类型拷贝,而将引用类型数据的地址拷贝给新对象,深拷贝则是将原对象及其数据属性全部完全独立地拷贝给新对象。

实现浅拷贝可以使用ES6中的拓展运算符和Object.assign()方法,深拷贝则可以使用JSON.parse(JSON.stringify(obj))和递归两种方式。无论实现哪种方式,需要注意拷贝的深度和循环引用引发的问题。