了解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)

关于Flex布局中紫色斜线区域的疑问在使用Flex布局时,你可能会遇到一些令人困惑的现象,比如在开发者工具(d...

在元素个数不固定的情况下如何通过CSS选择第一个指定类名的子元素在处理HTML结构时,常常会遇到元素个数不�...
