javascript - 为什么 JavaScript 中的不变性如此重要(或需要)?

标签 javascript reactjs functional-programming immutability immutable.js

我目前正在处理 React JSReact Native构架。在中途我遇到了 Immutability 或 Immutable-JS library ,当我阅读 Facebook 的 Flux 和 Redux 实现时。

问题是,为什么不变性如此重要?改变对象有什么问题?这不是让事情变得简单吗?

举个例子,让我们考虑一个简单的新闻阅读器应用,其起始屏幕是新闻标题的 ListView 。

如果我设置一个 对象数组 的值最初,我无法操作它。这就是不变性原理所说的,对吧? (如果我错了,请纠正我。) 但是,如果我有一个必须更新的新 News 对象怎么办?在通常情况下,我可以将对象添加到数组中。 在这种情况下我该如何实现?删除商店并重新创建它? 向数组中添加对象不是成本更低的操作吗?

最佳答案

我最近一直在研究同一主题。我会尽力回答您的问题并尝试分享我到目前为止所学到的知识。

The question is, why is immutability so important? What is wrong in mutating objects? Doesn't it make things simple?

基本上归结为不变性提高了可预测性、性能(间接)并允许进行突变跟踪这一事实。

可预测性

突变隐藏了变化,这会产生(意想不到的)副作用,这可能会导致令人讨厌的错误。当您强制执行不变性时,您可以使您的应用程序架构和心智模型保持简单,从而更容易推理您的应用程序。

性能

尽管向不可变对象(immutable对象)添加值意味着需要在需要复制现有值的地方创建一个新实例,并且需要将新值添加到新对象中,这会消耗内存,但不可变对象(immutable对象)可以利用结构共享以减少内存开销。

All updates return new values, but internally structures are shared to drastically reduce memory usage (and GC thrashing). This means that if you append to a vector with 1000 elements, it does not actually create a new vector 1001-elements long. Most likely, internally only a few small objects are allocated.

您可以阅读更多关于此 here 的信息.

突变跟踪

除了减少内存使用量之外,不变性还允许您通过使用引用和值相等来优化您的应用程序。这使得很容易查看是否有任何变化。例如, react 组件中的状态变化。您可以使用 shouldComponentUpdate 通过比较状态对象来检查状态是否相同,并防止不必要的渲染。 你可以阅读更多关于这个 here .

其他资源:

If I set say an array of objects with a value initially. I can't manipulate it. That's what immutability principle says, right?(Correct me if I am wrong). But, what if I have a new News object that has to be updated? In usual case, I could have just added the object to the array. How do I achieve in this case? Delete the store & recreate it? Isn't adding an object to the array a less expensive operation?

是的,这是正确的。如果您对如何在应用程序中实现这一点感到困惑,我建议您查看 redux这样做是为了熟悉核心概念,对我帮助很大。

我喜欢使用 Redux 作为示例,因为它包含不变性。它有一个单一的不可变状态树(称为store),其中所有状态更改都是通过调度由reducer 处理的操作来显式的,该reducer 接受先前的状态以及所述操作(一次一个)并返回应用程序的下一个状态。您可以阅读更多关于它的核心原则 here .

egghead.io 上有一个很棒的 redux 类(class)在哪里 Dan Abramov redux 的作者,对这些原则的解释如下(我稍微修改了代码以更好地适应场景):

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();

此外,这些视频更详细地演示了如何实现以下方面的不变性:

关于javascript - 为什么 JavaScript 中的不变性如此重要(或需要)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34385243/

相关文章:

javascript - 是否可以在 javascript 中测试 var 是否包含图像节点以及是否已加载?

javascript - 用es6写书架模型

javascript - 如何在 Javascript 对象数组中查找特定键的所有唯一值?

javascript - 使用 "Tab"单击执行 "Enter"键的操作,在 Bootstrap 行内

reactjs - 在react-redux中重新加载页面的正确方法是什么?

reactjs - React webpack 应用程序 public/images 与 src/images

scala - 函数式编程 : is foldLeft is the parent method of all functional methods such as foldRight, 映射、过滤器

haskell - 在 Haskell 中删除具有特定 Int 的树叶

reactjs - 如何从访问 token 中提取各种声明?

javascript - 过滤 object[array[@]] 为 nil 或空的数组