突变,但是它们到底是什么,它们是邪恶的吗? 在本文中,我们将涵盖可变分配和突变的概念,并查看为什么 - 一起 - 它们对开发人员来说可能是一个真正的痛苦。我们将研究如何管理它们以避免问题,如何使用尽可能少的以及如何保持代码可预测。 如果您想更详细地探索此主题,或者与Modern JavaScript提高速度,请查看我的新书的第一章,学习免费使用JavaScript。 >
让我们从回到价值类型的基础知识开始吧……>
钥匙要点
JavaScript值分类为原语(不变)和对象(可变),从而影响了可变分配和突变的行为。
使用“ const”不会阻止对象突变;它仅防止将变量重新分配到其他值或对象。
传播操作员(``…')对于创建对象的浅副本至关重要,从而避免了与复制划分的对象中的突变有关的问题。
突变本质上不是不好的,而应仔细管理以维持代码可预测性并最大程度地减少错误,尤其是在动态的Web应用程序中。>符号 - 一个独特的令牌,保证永远不会与另一个符号冲突
如果我将数字3分配给另一个变量,则引用与熊相同的值:
<span>const bears = 3; </span>
变量熊和火枪手都引用相同的原始值3。我们可以使用严格的等价运算符对此进行验证,===:
<span>let musketeers = 3; </span>
在使用对象时
时有些陷入困境此分配意味着变量Ghostbusters引用了一个对象:
bears <span>=== musketeers </span><span><< true </span>
但是,在将对象分配给变量时,一个很大的区别是,如果将另一个对象分配给另一个变量,它将引用一个完全不同的对象 - 即使两个对象文字看起来完全相同!例如,下面的作业看起来像变量TMNT(青少年突变体忍者神龟)引用与变量捉鬼敢死的对象:
<span>const ghostbusters = { number: 4 }; </span>
>变量重新分配
<span>let tmnt = { number: 4 }; </span>
> const声明的任何变量均不能重新分配到另一个值。这适用于原始值和对象。例如,变量熊在上一节中使用const声明,因此它不能为其分配另一个值。如果我们尝试将数字2分配给变量熊,我们会发现一个错误:
>同样适用于对象。如果我们尝试将另一个对象分配给变量Ghostbusters,则会得到相同的错误:
>当关键字用于声明变量时,可以将其重新分配以稍后在我们的代码中引用不同的值。例如,我们使用LET声明了可变的火枪手,因此我们可以更改火枪手所引用的价值。如果D'Artagnan加入了火枪手,他们的人数将增加到4:
ghostbusters <span>=== tmnt </span><span><< false </span>
这可以做到这一点,因为让我们用来声明变量。我们可以根据我们喜欢的次数改变火态引用的价值。
>也使用Let声明了变量TMNT,因此也可以重新分配以引用另一个对象(如果我们喜欢的话,或者完全是其他类型):
<span>const bears = 3; </span>
完全不同的对象;我们不仅将数字属性更改为5。 总而言之,如果您使用const声明一个变量,则无法重新分配其值,并且始终将引用最初分配给的相同原始值或对象。如果您使用LET声明一个变量,则可以根据程序后来要求将其值重新分配多次。
>通常将尽可能多地视为良好实践,因为这意味着变量的价值保持恒定,并且代码更加一致和可预测,从而使其不容易出现错误和错误。 通过参考 在本机JavaScript中,您只能为变量分配值。即使看起来可以,您也无法分配变量来引用另一个变量。例如,stooges的数量与火枪手的数量相同,因此我们可以使用以下内容来分配变量stooges以引用与变量火枪手相同的值:这看起来像变量stooges正在引用变量步枪仪,如下图所示:
<span>let musketeers = 3; </span>
这意味着,如果D'Artagnan加入了火枪手,并且我们将火枪手的价值设置为4,则Stooges的价值将保持3.实际上,因为我们使用const声明了Stooges变量,所以我们无法设置它具有任何新价值;它将永远是3 总结:如果您使用const声明变量并将其设置为原始值,即使是通过对另一个变量的引用,则其值无法更改。这对您的代码有益,因为这意味着它将更加一致和可预测。
突变
如果可以更改值,则说一个值为
>可变的。仅此而已:A突变
不变的:您永远无法更改其属性。例如,如果我们将字符串“蛋糕”分配给可变食品,我们可以看到我们无法更改其任何属性:
<span>const bears = 3; </span>
>但是,如果我们看一下变量的值,我们发现什么都没有改变:
<span>let musketeers = 3; </span>
如果我们尝试更改长度属性,也会发生同样的事情:
bears <span>=== musketeers </span><span><< true </span>
>尽管返回值表示已更改了长度的属性,但快速检查表明它没有:
<span>const ghostbusters = { number: 4 }; </span>
请注意,这与使用const而不是let声明变量无关。如果我们曾经使用过,我们可以将食物设置为引用另一根字符串,但我们无法更改其任何属性。不可能更改原始数据类型的任何属性,因为它们是不变的
<span>let tmnt = { number: 4 }; </span>
可变性和对象
相反,JavaScript中的所有对象都是可变的,这意味着即使使用const声明了它们的属性,也可以更改其属性(请记住,请记住并仅控制一个变量是否可以重新签名,并且与可变性)。例如,我们可以使用以下代码更改数组的第一项:
。
>我们也可以更改数组的长度属性,即使已使用const声明了数组:ghostbusters <span>=== tmnt </span><span><< false </span>
>通过参考复制 >请记住,当我们将变量分配给对象文字时,变量也将完全不同的对象引用,即使它们看起来相同:
>
bears <span>= 2; </span><span><< TypeError: Attempted to assign to readonly property. </span>
对象:
ghostbusters <span>= {number: 5}; </span><span>TypeError: Attempted to assign to readonly property. </span>
与变量TMNT引用的对象相同,而不是完全不同的对象。
这通常称为通过引用复制,因为两个变量都分配给引用
> samemusketeers <span>= 4; </span>
。
这很重要,因为对此对象进行的任何突变都将在两个变量中都可以看到。
>因此,如果蜘蛛侠加入神奇四侠,我们可能会更新对象中的数字值:
这是一个突变,因为我们已经更改了数字属性,而不是设置factand4来引用新对象。
<span>const bears = 3; </span>
这是因为TMNT和FANTANDY4都在引用相同的对象,因此任何对TMNT或FANTANDEN的突变都会影响它们两个。
>这突出了JavaScript中的一个重要概念:当对象通过参考复制并随后突变时,突变会影响任何引用该对象的任何其他变量。这可能会导致意外的副作用和难以追踪的错误。抢救的传播操作员!
>传播操作员是在ES2015中的阵列和字符串以及ES2018中的对象引入的。它使您可以轻松地制作对象的浅副本,而无需创建对原始对象的引用。
>下面的示例显示了我们如何设置可变factany4来引用tmnt对象的副本。该副本将与TMNT对象完全相同,但是fancally4将引用一个全新的对象。这是通过将要复制的变量的名称放置在对象中的文字中,并在其前面的传播操作员来完成:
>我们在这里实际完成的是将变量factally4分配给新对象文字,然后使用传播操作员复制TMNT变量引用的对象的所有枚举属性。由于这些属性是值,因此它们按值将其复制到奇妙的4个对象中,而不是通过参考。
<span>let musketeers = 3; </span>
>现在,对任何一个对象进行的任何更改都不会影响另一个对象。例如,如果我们将fandand4变量的数字属性更新为5,则不会影响tmnt变量:
bears <span>=== musketeers </span><span><< true </span>
>传播运算符还具有有用的快捷方式表示法,可用于制作对象的副本,然后在单个代码行中对新对象进行一些更改。
一样:
>我们可以通过添加引用在vread对象后要更改的属性来在一行中执行此操作。这是为变量Donatello和Raphael创建新对象的代码:
<span>const bears = 3; </span>
>请注意,以这种方式使用传播操作员只能使对象的浅副本。要进行深层副本,您必须递归进行此操作或使用库。就个人而言,我建议您尝试使物体尽可能浅。
突变不好?突变的声誉不好,但它们本身并不一定是不好的。实际上,如果您要构建动态的Web应用程序,则必须在某个时候改变。从字面上看,这就是“动态”一词的含义!这意味着您的代码中必须存在一些突变。话虽如此,突变越少,您的代码就会越容易预测,使维护更容易,并且不太可能开发任何错误。
一种特别有毒的组合正在通过参考和突变复制。这可能会导致您甚至没有意识到发生的副作用和错误。如果您突变代码中另一个变量引用的对象,则可能会导致许多可能难以追踪的问题。关键是尝试最大程度地减少您对突变的使用,并跟踪哪些物体已被突变。 在功能编程中,纯函数是不会引起任何副作用的功能,突变是副作用的最大原因之一。
黄金法则是避免通过参考复制任何对象。如果要复制另一个对象,请使用传播操作员,然后在制作副本后立即进行任何突变。
接下来,我们将研究JavaScript中的数组突变。
如果您想通过现代JavaScript加快速度,请不要忘记查看我的新书与JavaScript学习代码。您可以免费阅读第一章。如果您有任何疑问或评论,请在Twitter上与您联系!
经常询问有关JavaScript变量分配和突变的问题(常见问题解答)> JavaScript中的变量分配与突变之间有什么区别?例如,令x = 5;在这里,我们将值5分配给变量x。另一方面,突变是指更改现有变量价值的过程。例如,如果我们以后写x = 10;我们通过将其值从5更改为10来突变x。
>通过逐步传递和通过引用是JavaScript可以将变量传递到函数的两种方式。当JavaScript通过值通过变量时,它会创建变量值的副本,并将复制到函数的副本。对函数内部变量的任何更改都不会影响原始变量。但是,当JavaScript通过引用传递变量时,它将引用对变量的内存位置。因此,对函数内部变量的任何更改也会影响原始变量。
>
>如何在JavaScript中创建对象的深副本?在JavaScript中是使用JSON.PARSE()和JSON.STRINGIFY()方法。 JSON.STRINGIFY()方法将对象转换为JSON字符串,而JSON.PARSE()方法将JSON字符串转换回对象。这将创建一个新对象,它是原始对象的深副本。以上是JavaScript中可变分配和突变的指南的详细内容。更多信息请关注PHP中文网其他相关文章!