Appearance
Mutation
在上一讲属性的模块中,我们介绍了夏洛克·福尔摩斯搬到马里布的秘密,但我们还没有解释它。 这一次,我们将一步一步地浏览代码,并一起绘制图表,以便检查您的心智模型。
Step 1:声明 sherlock
变量
let sherlock = {
surname: 'Holmes',
address: { city: 'London' }
};
请根据你之间建立的心智模型画一下图
这是我的图👇
没有嵌套的对象
注意,我们这里不是一个,而是两个完全独立的对象。两对花括号表示两个对象。
Step 2:描述 john
变量
let john = {
surname: 'Watson',
address: sherlock.address
};
请根据你之间理建立的心智模型画一下图
这是我的图👇
属性总是指向值
记住:属性总是指向一个值!它不能指向另一个属性或变量。通常,我们宇宙中的所有导线都指向值。
Step 3:改变属性
john.surname = 'Lennon';
john.address.city = 'Malibu';
请根据你之间理建立的心智模型画一下图
这是我的图👇
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.address
和john.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。
- 在代码中突变你刚刚创建的对象是安全的。大体上,你会在多大程度上使用变异取决于你的应用程序的架构。