突變,但是它們到底是什麼,它們是邪惡的嗎? 在本文中,我們將涵蓋可變分配和突變的概念,並查看為什麼 - 一起 - 它們對開發人員來說可能是一個真正的痛苦。我們將研究如何管理它們以避免問題,如何使用盡可能少的以及如何保持代碼可預測。 如果您想更詳細地探索此主題,或者與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中文網其他相關文章!