Skip to content

Mutation

在上一讲属性的模块中,我们介绍了夏洛克·福尔摩斯搬到马里布的秘密,但我们还没有解释它。 这一次,我们将一步一步地浏览代码,并一起绘制图表,以便检查您的心智模型。

Step 1:声明 sherlock 变量

let sherlock = {
  surname: 'Holmes',
  address: { city: 'London' }
};

请根据你之间建立的心智模型画一下图

这是我的图👇

image-20220417171439346

没有嵌套的对象

注意,我们这里不是一个,而是两个完全独立的对象。两对花括号表示两个对象。

Step 2:描述 john变量

let john = {
  surname: 'Watson',
  address: sherlock.address
};

请根据你之间理建立的心智模型画一下图

这是我的图👇

image-20220417172052448

属性总是指向值

记住:属性总是指向一个值!它不能指向另一个属性或变量。通常,我们宇宙中的所有导线都指向值。

image-20220417172311159

Step 3:改变属性

john.surname = 'Lennon';
john.address.city = 'Malibu';

请根据你之间理建立的心智模型画一下图

这是我的图👇

image-20220417173136213

console.log(sherlock.surname); // "Holmes"
console.log(sherlock.address.city); // "Malibu"
console.log(john.surname); // "Lennon"
console.log(john.address.city); // "Malibu"

Mutation

突变是"改变"的一种奇特说法

例如,我们可以说我们change了一个对象的属性,或者我们可以说我们mutated了那个对象(及其属性)。这是一样的。

人们喜欢说“mutate”,因为这个词有一种不祥的意味。它提醒你要格外小心。这并不意味着突变是“坏的”——它只是编程!但你需要非常有意识的去做。

让我们回顾一下最初的任务。我们想给约翰换个姓,然后把他搬到马里布。现在让我们看看我们的两个mutations:

// Step 3: Changing the Properties
john.surname = 'Lennon';
john.address.city = 'Malibu';

哪些对象在这里被改变了?

第一行修改了john所指向的对象。它的意思是:我们想要改变约翰的姓氏。该对象表示John的数据,因此我们改变了它的姓氏属性。

然而,第二行做了一些非常不同的事情。它不会改变john指向的对象。相反,它改变了一个完全不同的对象——我们可以通过john.address访问的对象。如果我们看一下上面我们画的图,我们知道我们将通过sherlock.addressjohn.address将指向相同的对象!

通过改变程序中其他地方使用的对象,我们弄得一团糟。

有趣的事实

这就是为什么对象被“嵌套”的直觉是如此错误!它让我们忘记了可能有很多对象指向我们更改过的对象。

所以对象只是值的集合,并不是值存在于对象

可能的解决方案:改变另一个对象

// Replace Step 3 with this code:
john.surname = 'Lennon';
john.address = { city: 'Malibu' };

替代解决方案:没有对象突变

// Replace Step 3 with this code:
john = {
  surname: 'Lennon',
  address: { city: 'Malibu' }
};

现在在打印下面的值就会发现

console.log(sherlock.surname); // "Holmes"
console.log(sherlock.address.city); // "London"
console.log(john.surname); // "Lennon"
console.log(john.address.city); // "Malibu"

Mutation 是很坏的么

  • 不要以为突变是 "坏事 "就走了。那是一种懒惰的过度简化,掩盖了真正的理解。如果数据随时间变化,某处就会发生变异。问题是,什么应该被突变,在哪里,以及什么时候?

  • 当你突变一个对象时,变量和属性可能已经指向它了。你的突变会影响以后 "跟随 "这些线的任何代码。

  • 这既是一种祝福也是一种诅咒。变异使改变一些数据变得很容易,并能立即在整个程序中 "看到 "这种变化。然而,无纪律的突变使我们更难预测程序会做什么。

  • 有一个学派认为,突变最好被限制在你的应用程序的一个非常狭窄的层。根据这一理念,其好处是你的程序的行为更容易预测。缺点是你要写更多的代码来 "传递东西 "和避免变异。

  • 值得注意的是,突变你刚刚创建的新对象总是可以的,因为现在还没有其他的线指向它们。在其他情况下,我建议你对你要突变的东西和时间要非常谨慎。你对变异的依赖程度取决于你的应用程序的架构。

回顾

  • 在我们的宇宙中,对象从来都是 不是"嵌套 "的
  • 改变一个对象的属性也被称为突变该对象。
  • 如果你改变了一个对象,你的代码将通过任何指向该对象的线来 "看到 "这一变化。有时,这可能是你想要的。然而,突变意外的共享数据可能会导致bug。
  • 你可以用const而不是let来声明一个变量。这允许你强制这个变量总是指向同一个值。但请记住,const并不能阻止对象的变异!你可以用const来声明一个变量,而不是用let。
  • 在代码中突变你刚刚创建的对象是安全的。大体上,你会在多大程度上使用变异取决于你的应用程序的架构。

Released under the MIT License.