了解JavaScript中的不變性
JavaScript 中的不變性概念可能與變量重新賦值容易混淆。使用let
或var
聲明的變量可以重新賦值,但const
聲明的變量則不行。
例如,將"Kingsley" 賦值給名為firstName
的變量:
let firstName = "Kingsley";
可以重新賦值:
firstName = "John";
這是因為使用了let
。如果使用const
:
const lastName = "Silas";
嘗試重新賦值會報錯:
lastName = "Doe"; // TypeError: Assignment to constant variable.
但這並非不變性。
在React 等框架中,一個重要概念是避免直接修改狀態(state) 和屬性(props)。 不變性並非React 獨有概念,而是React 在處理狀態和屬性時所利用的一個重要原則。
那麼,不變性究竟是什麼意思呢?
不變性:堅持事實
不變數據無法改變其結構或其中的數據。它將值賦給一個不能更改的變量,使該值成為一個事實,或某種意義上的真相來源——就像公主親吻青蛙,希望它變成英俊的王子一樣。不變性意味著青蛙將永遠是青蛙。
而對象和數組允許變異,這意味著數據結構可以更改。如果我們告訴它,親吻這些青蛙中的任何一個都可能導致變成王子的轉變。
例如,一個用戶對象:
let user = { name: "James Doe", location: "Lagos" };
創建一個新的newUser
對象:
let newUser = user;
如果第一個用戶更改位置,它將直接修改user
對象,並影響newUser
:
user.location = "Abia"; console.log(newUser.location); // "Abia"
這可能不是我們想要的結果。這種重新賦值可能會導致意外後果。
使用不變對象
我們需要確保對像不被變異。如果要使用某個方法,它必須返回一個新對象。本質上,我們需要一個純函數。
純函數具有兩個特性:
- 返回值取決於傳入的參數。只要輸入不變,返回值就不會改變。
- 它不會更改其作用域之外的事物。
使用Object.assign()
,我們可以創建一個不會修改傳入對象的函數。它將創建一個新的對象,並將第二個和第三個參數複製到作為第一個參數傳入的空對像中,然後返回新對象。
const updateLocation = (data, newLocation) => { return Object.assign({}, data, { location: newLocation }); };
updateLocation()
是一個純函數。如果我們傳入第一個用戶對象,它將返回一個新的用戶對象,其中location
屬性具有新值。
另一種方法是使用擴展運算符:
const updateLocation = (data, newLocation) => { return { ...data, location: newLocation }; };
那麼,這與React 有什麼關係呢?
React 中的不變性
在典型的React 應用中,狀態是一個對象。 (Redux 使用不變對像作為應用程序存儲的基礎。)React 的協調過程確定組件是否應該重新渲染,或者它是否需要一種跟踪更改的方法。
換句話說,如果React 無法確定組件的狀態已更改,那麼它將不知道要更新虛擬DOM。
強制執行不變性使得跟踪這些更改成為可能。這允許React 比較對象的舊狀態及其新狀態,並根據該差異重新渲染組件。
這就是為什麼通常不建議直接更新React 中的狀態:
this.state.username = "jamesdoe";
React 將不確定狀態是否已更改,並且無法重新渲染組件。
Immutable.js
Redux 遵循不變性的原則。它的reducer 應該是純函數,因此它們不應修改當前狀態,而應根據當前狀態和action 返回一個新對象。我們通常會像前面那樣使用擴展運算符,但是可以使用名為Immutable.js 的庫來實現相同的效果。
雖然純JavaScript 可以處理不變性,但在過程中可能會遇到一些陷阱。使用Immutable.js保證不變性,同時提供一個性能優越的豐富API。本文不會詳細介紹Immutability.js 的所有細節,但我們將看一個簡單的示例,演示如何在由React 和Redux 提供支持的任務應用程序中使用它。
首先,讓我們從導入所需的模塊並設置Todo 組件開始。
const { List, Map } = Immutable; const { Provider, connect } = ReactRedux; const { createStore } = Redux;
如果在本地機器上操作,則需要安裝這些包:
npm install redux react-redux immutable
導入語句如下所示:
import { List, Map } from "immutable"; import { Provider, connect } from "react-redux"; import { createStore } from "redux";
然後,我們可以繼續使用一些標記設置我們的Todo 組件:
// ... Todo 組件代碼...
我們使用handleSubmit()
方法創建新的待辦事項。在本例中,用戶將只創建新的待辦事項,我們只需要一個操作:
// ... actions 代碼...
我們創建的有效負載包含待辦事項的ID 和文本。然後,我們可以繼續設置reducer 函數並將我們上面創建的操作傳遞給reducer 函數:
// ... reducer 代碼...
我們將使用connect
創建一個容器組件,以便我們可以連接到存儲。然後,我們需要傳入mapStateToProps()
和mapDispatchToProps()
函數來連接。
// ... connect 代碼...
我們使用mapStateToProps()
為組件提供存儲的數據。然後,我們使用mapDispatchToProps()
通過將操作綁定到它來使操作創建者作為屬性可用於組件。
在reducer 函數中,我們使用來自Immutable.js 的List
來創建應用程序的初始狀態。
// ... reducer 代碼...
將List
視為JavaScript 數組,這就是為什麼我們可以在state
上使用.push()
方法的原因。用於更新狀態的值是一個對象,它繼續說明Map
可以被識別為一個對象。這樣,無需使用Object.assign()
或擴展運算符,因為它保證了當前狀態不會改變。這看起來簡潔得多,尤其是在狀態嵌套得很深的情況下——我們不需要在所有地方都使用擴展運算符。
不變狀態使代碼能夠快速確定是否發生了更改。我們不需要對數據進行遞歸比較來確定是否發生了更改。也就是說,重要的是要提到,在處理大型數據結構時,您可能會遇到性能問題——複製大型數據對像是有代價的。
但是數據需要更改,因為否則不需要動態站點或應用程序。重要的是如何更改數據。不變性提供了更改應用程序數據(或狀態)的正確方法。這使得跟踪狀態的更改並確定應用程序的哪些部分應該由於該更改而重新渲染成為可能。
第一次學習不變性會令人困惑。但是,當狀態發生變異時,您會遇到彈出的錯誤,這會讓您變得更好。這通常是理解不變性的需求和好處最清晰的方式。
進一步閱讀
- React 和Redux 中的不變性
- Immutable.js 101 – Maps 和Lists
- 使用Immutable.js 與Redux
請注意,由於原文包含大量代碼塊,為了保持偽原創性並避免過度重複,我簡化了一些代碼塊的描述,並對部分語句進行了同義詞替換和句式調整。 圖片格式保持不變。
以上是了解JavaScript中的不變性的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

您是否曾經在項目上需要一個倒計時計時器?對於這樣的東西,可以自然訪問插件,但實際上更多

在元素個數不固定的情況下如何通過CSS選擇第一個指定類名的子元素在處理HTML結構時,常常會遇到元素個數不�...

關於Flex佈局中紫色斜線區域的疑問在使用Flex佈局時,你可能會遇到一些令人困惑的現象,比如在開發者工具(d...

格子呢是一塊圖案布,通常與蘇格蘭有關,尤其是他們時尚的蘇格蘭語。在Tartanify.com上,我們收集了5,000多個格子呢
