JavaScript 中对象变异的介绍

在编程中,对象变异意味着对象在创建后其状态或数据发生了变异。换句话说,在JavaScript中改变对象属性的操作被称为对象变异。对象变异直接改变对象的值,这使得在多个操作可能同时尝试读取或写入对象的应用程序中变得具有挑战性。

本文讨论了JavaScript中对象变异的相关内容,并在必要时提供相关的代码示例。

JavaScript中的数据类型

数据类型表示变量或对象可以保存的数据类型。JavaScript支持两种不同的数据类型类别:原始类型和用户定义或引用类型。JavaScript支持两种不同的数据类型类别:原始类型和用户定义或引用类型。

原始数据类型

在JavaScript中,所有的原始数据类型本质上是不可变的,即在创建后无法更改。数字、布尔值、字符串、大整数、未定义、空值、符号和对象都是原始类型的示例。

用户定义或引用数据类型

用户定义的数据类型或引用数据类型是使用原始类型或原始和用户定义类型的组合创建的对象。用户定义或引用类型的典型示例是对象和数组。

JavaScript中变量的赋值和重新赋值方式

当您将一个原始类型变量赋值给另一个原始类型变量时,这两个变量保存相似的值,但它们存储在不同的存储位置。例如,假设您有两个变量varAvarB,并以以下方式将一个变量分配给另一个:

JavaScript

 

当执行上述代码段时,控制台将显示数字100。现在,您更改其中一个变量的值(比如varB)如下所示。

JavaScript

 

请注意变量varB的值已更改为500。当打印varA的值时,它仍然显示为100。这是因为这些变量varAvarB存储在两个不同的内存位置。因此,如果更改任何一个变量,新值或更改的值不会反映在其他变量上。

JavaScript中的对象突变是什么?

在JavaScript中,对象的数据类型可以属于两种类别之一:原始或非原始。虽然原始类型是不可变的,即创建后无法更改,但您可以更改非原始类型,即对象和数组。对象始终允许更改其值。因此,您可以更改可变类型的字段状态,而无需创建新实例。

对象突变可能会导致一些问题,例如以下问题:

  • 由于并发和线程安全问题,突变的对象通常会导致竞态条件
  • 突变可能会在源代码中引入复杂性,因为存在不可预测性和线程安全问题。
  • 突变通常会导致难以在应用程序源代码中识别的错误。
  • 突变使得测试和调试代码变得困难,因为跟踪利用突变的代码变成了一项挑战。

演示对象突变的代码示例

对象突变可能发生在以下任何情况下:

  • 添加、编辑或删除属性
  • 使用可能导致突变的方法

当您直接或间接地更改对象的属性时,实质上是在改变对象。下面的代码片段展示了如何通过更改其属性来突变对象。

JavaScript

 

在上述代码片段中,我们创建了一个名为author的对象,其中包含两个属性,即idname。其中id属性用于存储作者记录的idname属性存储作者的姓名。请注意我们如何通过改变与id属性相关的值来突变author对象。接下来,我们向author对象添加一个名为city的新属性,并为该属性赋值。

当您运行上述代码片段时,author对象的属性及其值将如下所示:

JavaScript

 

当您在JavaScript中将对象传递给函数或将其赋值给变量时,实质上是将对象的引用传递给了函数或变量,而不是对象的副本。这意味着通过传递对象或将其赋值给变量创建的新对象所做的任何更改都将应用于实际对象的所有引用。

考虑以下代码片段,展示了如何在JavaScript中创建对象,然后将其赋值给变量。

JavaScript

 

在上述代码片段中,对象objA被赋值给objB,并且更改了objA的pincode属性的值,即对象objA被改变。当您执行该程序时,将显示以下数据。

JavaScript

 

请注意pincode属性的值已更改。

防止JavaScript中的对象突变

在JavaScript中,您可以通过以下几种方式防止突变:

  • 利用Object.assign()方法或展开运算符(…)进行对象克隆
  • 使用Object.seal()方法防止向对象添加或删除属性
  • 使用Object.freeze()方法防止向对象添加、编辑或删除属性

使用克隆

参考以下代码片段,展示了如何使用展开运算符在JavaScript中克隆对象

JavaScript

 

在这里,克隆对象的名称是clonedObj,它与名为originalObj的原始对象相同。因此,如果您显示这两个对象的两个属性的值,结果将是相同的。

现在,将克隆对象clonedObj的一个属性的值更改为您想要的值,如下面给出的代码片段所示。

Plain Text

 

现在,编写以下代码以显示两个对象originalObjclonedObj的名为x的属性的值。

Plain Text

 

当您运行程序时,您会注意到原始对象中属性x的值未更改。结果将如下所示显示在控制台上:

Plain Text

 

使用Object.freeze()方法

Object.freeze()方法可以通过阻止对其任何属性的更改来使对象不可变。

JavaScript

 

当您执行前面的代码片段时,结果将类似于这样:

JavaScript

 

从输出中可以看出,即使您已为属性city和state以及pincode分配了值,也不会产生任何效果。因此,对象的任何属性中包含的数据都没有发生任何更改。

使用Object.seal()方法

您还可以使用Object.seal()方法来防止JavaScript中的对象变异。此方法将允许您更改现有属性的值,但您不能修改或删除任何对象的属性。下面的代码示例说明了这一点:

JavaScript

 

在上述代码片段中,虽然允许修改名为author的对象的属性,但不允许添加或删除对象的属性。运行程序时,您会看到修改的属性值反映在结果中,但添加或删除属性的语句将被忽略。在控制台上输出如下:

JavaScript

 

使用Object.defineProperty()方法

您还可以利用JavaScript中的Object.defineProperty()方法来控制对象各个属性的可变性。以下代码片段展示了如何使用该方法来禁止修改受限属性中包含的值。

JavaScript

 

执行上述代码片段后,您将在控制台上看到数字3的显示。

要点

  • JavaScript将对象类型分为两个不同的类别:基本数据类型(可变)和对象(不可变)。
  • 对象变异一词指的是在创建后修改或更改对象的操作。
  • 虽然诸如数字等基本值不能被改变,但您可以随时更改对象。
  • 由于JavaScript中的字符串是不可变的,因此一旦创建就无法更改它们。
  • 虽然变异本身并不那么糟糕,但您应谨慎管理以减少应用程序中的错误。
  • 您可以通过遵循推荐做法和利用不可变数据结构来减少或消除JavaScript中的变异。

Source:
https://dzone.com/articles/an-introduction-to-object-mutation-in-javascript