【专栏】Javascript 对象的深浅拷贝的区别以及如何实现它们

简介: 【4月更文挑战第29天】JavaScript中的对象拷贝分为浅拷贝和深拷贝。浅拷贝仅复制对象引用,修改拷贝会影响原始对象,如使用直接赋值、`Object.assign()`、扩展运算符和`Array.prototype.concat()`。深拷贝则创建独立副本,修改不影响原始对象,可通过递归、`JSON.stringify()`和`JSON.parse()`、Lodash的`cloneDeep()`或jQuery的`jQuery.extend()`实现。

在 JavaScript 中,对象的拷贝是一个常见的操作。拷贝对象可以避免对原始对象的意外修改,同时也可以在不同的上下文中使用相同的数据。在 JavaScript 中,有两种常见的拷贝方式:浅拷贝和深拷贝。本文将详细介绍这两种拷贝方式的区别以及如何实现它们。

一、浅拷贝

浅拷贝是指创建一个新的对象,该对象的属性值与原始对象的属性值相同,但它们指向的是同一个内存地址。换句话说,浅拷贝只是复制了对象的引用,而不是对象本身。当我们修改浅拷贝对象的属性时,原始对象的属性也会相应地改变。以下是一些常见的浅拷贝方法:

  1. 直接赋值:这是最简单的浅拷贝方式,我们可以将一个对象直接赋值给另一个对象。例如:
let originalObject = {
    name: "John", age: 30 };
let shallowCopy = originalObject;

在这个例子中,shallowCopyoriginalObject 的浅拷贝。当我们修改 shallowCopy 对象的属性时,originalObject 对象的属性也会相应地改变。

  1. Object.assign()Object.assign() 方法是 ES6 中引入的一个对象合并方法,它也可以用于浅拷贝。例如:
let originalObject = {
    name: "John", age: 30 };
let shallowCopy = Object.assign({
   }, originalObject);

在这个例子中,shallowCopyoriginalObject 的浅拷贝。当我们修改 shallowCopy 对象的属性时,originalObject 对象的属性也会相应地改变。

  1. 扩展运算符(...):扩展运算符(...)也可以用于浅拷贝。例如:
let originalObject = {
    name: "John", age: 30 };
let shallowCopy = {
    ...originalObject };

在这个例子中,shallowCopyoriginalObject 的浅拷贝。当我们修改 shallowCopy 对象的属性时,originalObject 对象的属性也会相应地改变。

  1. Array.prototype.concat()Array.prototype.concat() 方法用于连接两个或多个数组,并返回一个新的数组。如果我们只传递一个数组作为参数,那么它也可以用于浅拷贝数组。例如:
let originalArray = [1, 2, 3];
let shallowCopy = originalArray.concat();

在这个例子中,shallowCopyoriginalArray 的浅拷贝。当我们修改 shallowCopy 数组的元素时,originalArray 数组的元素也会相应地改变。

二、深拷贝

深拷贝是指创建一个新的对象,该对象的属性值与原始对象的属性值相同,但它们指向的是不同的内存地址。换句话说,深拷贝创建了一个与原始对象完全独立的副本,当我们修改深拷贝对象的属性时,不会影响原始对象的属性。以下是一些常见的深拷贝方法:

  1. 递归实现:我们可以使用递归的方式来实现深拷贝。例如:
function deepCopy(obj) {
   
  if (typeof obj!== "object" || obj === null) {
   
    return obj;
  }
  let result = Array.isArray(obj)? []: {
   };
  for (let key in obj) {
   
    if (obj.hasOwnProperty(key)) {
   
      result[key] = deepCopy(obj[key]);
    }
  }
  return result;
}

在这个例子中,deepCopy() 函数接受一个对象作为参数,并返回一个深拷贝后的对象。如果参数不是对象或为空,则直接返回参数。否则,创建一个新的对象,并遍历参数对象的所有属性。如果属性的值是基本类型,则直接将其赋值给新对象的相应属性。如果属性的值是引用类型,则递归调用 deepCopy() 函数来创建该属性的深拷贝,并将其赋值给新对象的相应属性。

  1. JSON.stringify() 和 JSON.parse():我们可以使用 JSON.stringify()JSON.parse() 方法来实现深拷贝。例如:
let originalObject = {
    name: "John", age: 30, nestedObject: {
    sex: "男", country: "中国" } };
let deepCopy = JSON.parse(JSON.stringify(originalObject));

在这个例子中,deepCopyoriginalObject 的深拷贝。当我们修改 deepCopy 对象的属性时,不会影响 originalObject 对象的属性。

  1. Lodash 的 cloneDeep() 函数Lodash 是一个常用的 JavaScript 库,它提供了许多实用的函数,包括 cloneDeep() 函数,用于创建原始对象的完全独立副本,确保修改拷贝对象的属性不会影响原始对象。例如:
// 引入 Lodash
const _ = require('lodash');

// 原始对象
const originalObject = {
   
  name: '李华',
  age: 30,
  nestedObject: {
   
    sex: '男',
    country: '中国'
  }
};

// 使用 Lodash 的深拷贝函数 _.cloneDeep()
const deepCopyObject = _.cloneDeep(originalObject);

// 修改拷贝对象的某些属性
deepCopyObject.name = '李明';
deepCopyObject.nestedObject.sex = '女';

// 打印原始对象和拷贝对象,观察是否相互影响
console.log('原始对象:', originalObject);
console.log('深拷贝对象:', deepCopyObject);

在这个例子中,deepCopyObjectoriginalObject 的深拷贝。当我们修改 deepCopyObject 对象的属性时,不会影响 originalObject 对象的属性。

  1. jQuery 实现:虽然 jQuery 没有提供专门的深拷贝函数,但我们可以使用 jQuery.extend() 函数来实现浅拷贝,结合递归来实现深拷贝。例如:
// 原始对象
const originalObject = {
   
  name: '李华',
  age: 30,
  nestedObject: {
   
    sex: '男',
    country: '中国'
  }
};

// 使用 jQuery.extend() 进行深拷贝
var deepCopyObject = jQuery.extend(true, {
   }, originalObject);

// 修改拷贝对象的某些属性
deepCopyObject.name = '李明';
deepCopyObject.nestedObject.sex = '女';

// 打印原始对象和拷贝对象,观察是否相互影响
console.log('原始对象:', originalObject);
console.log('深拷贝对象:', deepCopyObject);

在这个例子中,deepCopyObjectoriginalObject 的深拷贝。当我们修改 deepCopyObject 对象的属性时,不会影响 originalObject 对象的属性。

相关文章
|
20小时前
|
设计模式 JavaScript 前端开发
JavaScript原型模式:实现对象共享属性和方法!
JavaScript原型模式:实现对象共享属性和方法!
|
2天前
|
JavaScript 前端开发
js用Date对象处理时间
以上就是JavaScript中Date对象处理时间的一些基本方法。
5 0
|
2天前
|
JavaScript 前端开发 开发者
.js 文件和 .mjs 文件的区别
.js 文件和 .mjs 文件的区别
15 0
|
2天前
|
JavaScript 前端开发
在JavaScript中,函数原型(Function Prototype)是一个特殊的对象
【5月更文挑战第11天】JavaScript中的函数原型是一个特殊对象,它为所有函数实例提供共享的方法和属性。每个函数在创建时都有一个`prototype`属性,指向原型对象。利用原型,我们可以向所有实例添加方法和属性,实现继承。例如,我们定义一个`Person`函数,向其原型添加`greet`方法,然后创建实例`john`和`jane`,它们都能调用这个方法。尽管可以直接在原型上添加方法,但推荐在构造函数内部定义以封装数据和逻辑。
18 2
|
2天前
|
JavaScript 前端开发
JavaScript 提供了多种方法来操作 DOM(文档对象模型)
【5月更文挑战第11天】JavaScript 用于DOM操作的方法包括获取元素(getElementById, getElementsByClassName等)、修改内容(innerHTML, innerText, textContent)、改变属性、添加/删除元素(appendChild, removeChild)和调整样式。此外,addEventListener用于监听事件。注意要考虑兼容性和性能当使用这些技术。
9 2
|
2天前
|
移动开发 JavaScript 前端开发
uni-app和Vue.js二者之间有什么区别?
1. uni-app是一个使用Vue.js开发所有前端应用的框架,支持一次编译多端运行。开发者编写的基础代码只需进行一次编写,就可以发布到多个平台,包括App、H5、微信小程序等。 2. Vue.js是一个渐进式JavaScript框架,用于构建用户界面。与其他大型框架不同的是,Vue被设计为可以自底向上逐层应用。
5 0
|
2天前
|
Web App开发 JavaScript 前端开发
Ecmascript 和javascript的区别
Ecmascript 和javascript的区别
10 0
|
2天前
|
JavaScript 前端开发
JS中浅拷贝和深拷贝的区别,浅拷贝的危害
JS中浅拷贝和深拷贝的区别,浅拷贝的危害
12 0
|
2天前
|
存储 JavaScript 前端开发
JavaScript对象方法详解
JavaScript对象方法详解
16 1
|
2天前
|
JavaScript
js多维数组去重并使具有相同属性的对象数量相加
js多维数组去重并使具有相同属性的对象数量相加
11 1