为什么在JavaScript中不可变性如此重要(或必需)?

273

我目前正在使用 React JSReact Native 框架进行开发。在半路上,我遇到了不可变性或者Immutable-JS库,当我在阅读Facebook的Flux和Redux实现时。

问题是,为什么不可变性那么重要?改变对象有什么不对吗?这难道不会使事情更加简单吗?

举个例子,我们考虑一个简单的新闻阅读器应用程序,打开屏幕是新闻标题的列表视图。

如果我设置一个对象数组初始值,我就不能对它进行操作。这就是不可变性原则所说的,对吗?(请纠正我如果我错了)。 但是,如果我有一个需要更新的新闻对象呢?通常情况下,我可以把这个对象添加到数组中。 在这种情况下,我该怎么办?删除存储并重新创建它吗? 把一个对象添加到数组中不是一个更少消耗资源的操作吗?


9
相关链接:http://programmers.stackexchange.com/questions/151733/if-immutable-objects-are-good-why-do-people-keep-creating-mutable-objects为什么人们会不断创建可变对象?如果不可变对象是好的,那么这些对象为什么还存在? - Mulan
3
不变数据结构和纯函数会导致引用透明性,使得程序行为的推理变得更加简单。在使用函数式数据结构时,您还可以免费获得回溯能力。 - WorBlux
我在@bozzmob提供了一个Redux的观点。 - prosti
1
学习不变性在函数式编程中作为一个概念可能很有用,而不是尝试认为JS与之相关。React是由函数式编程的粉丝编写的。要理解他们,你必须知道他们知道的内容。 - Gherman
这不是必要的,但它确实提供了一些不错的折衷方案。可变状态对于软件就像运动部件对于硬件一样 - Kristian Dupont
从ReactJS的角度来思考。如果您返回具有不同内容的相同对象,它如何知道您添加了一个项目。您必须告诉它数组已更改并且需要重新渲染。如果在某些深度嵌套数据中发生更改(例如建议计数),则比较会很慢,因为您需要遍历整个数组。但是使用不可变原则,您别无选择,只能返回新对象。现在,React框架可以通过执行指针地址比较轻松地知道它需要重新渲染,这非常快速。 - yiwen
13个回答

0

我创建了一个框架不可知的开源(MIT)库,用于可变(或不可变)状态,可以替换所有那些不可变存储库(如redux、vuex等)。

对我来说,不可变状态很丑陋,因为需要做太多的工作(大量的操作用于简单的读/写操作),代码不够可读,对于大型数据集的性能也无法接受(整个组件重新渲染 :/ )。

使用deep-state-observer,我可以使用点符号更新一个节点并使用通配符。我还可以创建状态历史记录(撤消/重做/时间旅行),仅保留已更改的具体值{path:value} = 更少的内存使用。

使用deep-state-observer,我可以微调事物,并对组件行为进行精细控制,从而可以大大提高性能。代码更易读,重构也更容易 - 只需搜索和替换路径字符串(无需更改代码/逻辑)。


0

不可变性的主要优点是其简单性。

替换对象比修改现有对象更简单。

它使您可以专注于一个地方的正确性。而不是可能更改对象的每个可能的地方。

如果您的对象处于无效状态,则更容易修复,因为故障必须在创建它时发生(因为它是不可变的)


-1

我认为支持不可变对象的主要原因是保持对象状态的有效性。

假设我们有一个名为arr的对象。当所有项都是相同的字母时,此对象是有效的。

// this function will change the letter in all the array
function fillWithZ(arr) {
    for (var i = 0; i < arr.length; ++i) {
        if (i === 4) // rare condition
            return arr; // some error here

        arr[i] = "Z";
    }

    return arr;
}

console.log(fillWithZ(["A","A","A"])) // ok, valid state
console.log(fillWithZ(["A","A","A","A","A","A"])) // bad, invalid state

如果arr变成不可变对象,那么我们就可以确保arr始终处于有效状态。

我认为每次调用 fillWithZ 时,arr 都会被改变。 - rodrigo-silveira
如果您使用immutable.js,每次更改对象时都会获得一个新副本。因此原始对象保持不变。 - bedorlan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接