我最近也在研究同样的话题。我会尽我最大的努力回答你的问题,并尝试分享我到目前为止学到的东西。
问题是,为什么不变性如此重要?有什么问题
变异的对象?这不是让事情变得简单了吗?
基本上可以归结为这样一个事实:不可变性增加了可预测性、性能(间接地),并允许突变跟踪。
可预测性
突变隐藏了更改,而更改会产生(意想不到的)副作用,从而导致严重的bug。当您强制执行不可变性时,您可以保持应用程序架构和心理模型的简单性,这使您更容易对应用程序进行推理。
性能
尽管向不可变对象添加值意味着需要创建一个新实例,其中需要复制现有值,并且需要向新对象添加新值,这会消耗内存,但不可变对象可以利用结构共享来减少内存开销。
所有更新都返回新值,但内部结构共享给
大幅度减少内存使用(和GC抖动)。这意味着如果
你附加到一个有1000个元素的向量,它实际上并不创建
一个新的向量,长度为1001个元素。最有可能的是,内部只有几个
分配小对象。
你可以在这里阅读更多相关内容。
突变跟踪
除了减少内存使用外,不可变性还允许您通过使用引用和值相等来优化应用程序。这使得查看是否有任何更改非常容易。例如,react组件的状态变化。您可以使用shouldComponentUpdate通过比较状态对象来检查状态是否相同,并防止不必要的呈现。
你可以在这里阅读更多相关内容。
额外的资源:
不变之道
不可变数据结构和JavaScript
JavaScript中的不可变性
如果我在初始值中设置一个对象数组。我不能
对它进行操作。这就是不可变原理,对吧?(正确的
如果我错了,请告诉我)。但是,如果我有一个新的News对象
被更新吗?通常情况下,我可以将对象添加到
数组中。在这种情况下我该如何实现呢?删除商店并重新创建它?
向数组中添加对象难道不是一种成本较低的操作吗?
是的,这是正确的。如果你对如何在你的应用程序中实现这一点感到困惑,我建议你看看redux是如何做到这一点的,以熟悉核心概念,它对我有很大帮助。
我喜欢使用Redux作为例子,因为它包含了不变性。它有一个单一的不可变的状态树(称为存储),其中所有的状态变化都是通过分派操作来显式的,这些操作由reducer处理,reducer接受前一个状态和所述操作(一次一个)并返回应用程序的下一个状态。你可以在这里阅读更多关于它的核心原则。
在egghead上有一门很好的redux课程。redux的作者Dan Abramov解释了这些原则如下(我修改了一些代码以更好地适应场景):
import React from 'react';
import ReactDOM from 'react-dom';
// Reducer.
const news = (state=[], action) => {
switch(action.type) {
case 'ADD_NEWS_ITEM': {
return [ ...state, action.newsItem ];
}
default: {
return state;
}
}
};
// Store.
const createStore = (reducer) => {
let state;
let listeners = [];
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(cb => cb !== listener);
};
};
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach( cb => cb() );
};
dispatch({});
return { subscribe, getState, dispatch };
};
// Initialize store with reducer.
const store = createStore(news);
// Component.
const News = React.createClass({
onAddNewsItem() {
const { newsTitle } = this.refs;
store.dispatch({
type: 'ADD_NEWS_ITEM',
newsItem: { title: newsTitle.value }
});
},
render() {
const { news } = this.props;
return (
<div>
<input ref="newsTitle" />
<button onClick={ this.onAddNewsItem }>add</button>
<ul>
{ news.map( ({ title }) => <li>{ title }</li>) }
</ul>
</div>
);
}
});
// Handler that will execute when the store dispatches.
const render = () => {
ReactDOM.render(
<News news={ store.getState() } />,
document.getElementById('news')
);
};
// Entry point.
store.subscribe(render);
render();
此外,这些视频进一步详细演示了如何实现不变性:
数组
对象