当前位置: 首页 > 面试题库 >

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

闻人修平
2023-03-14
问题内容

我目前正在研究React JS和React
Native
框架。在阅读关于Facebook的Flux和Redux实现的文章时,我遇到了Immutability或Immutable-
JS库

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

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

如果我设置说 最初 具有值 的对象数组,
我将无法对其进行操作。这就是不变性原则的意思,对吗?(如果我错了,请纠正我。)但是,如果我有一个新的News对象必须更新怎么办?在通常情况下,我可以将对象添加到数组中。在这种情况下我该如何实现?删除商店并重新创建?是不是将对象添加到数组中的开销较小?


问题答案:

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

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

基本上可以归结为不变性增加了(间接)可预测性,性能和允许进行突变跟踪的事实。

可预测性

突变会隐藏变化,从而产生(意外的)副作用,这可能会导致讨厌的错误。当您实施不变性时,可以使您的应用程序体系结构和思维模型保持简单,这使得对应用程序的推理更加容易。

性能

尽管向不可变对象添加值意味着需要在需要复制现有值的情况下创建新实例,并且需要向新对象添加新值,这会消耗内存,但不可变对象可以利用结构共享来减少内存高架。

所有更新都返回新值,但是内部结构被共享以大大减少内存使用(和GC崩溃)。这意味着,如果将一个向量附加到具有1000个元素的向量上,则实际上不会创建1001个元素长的新向量。内部很可能只分配了几个小对象。

您可以在此处了解更多信息。

变异追踪

除了减少内存使用量之外,不变性还允许您通过使用引用和值相等来优化应用程序。这使得查看任何更改是否真的很容易。例如,反应组件的状态变化。您可以shouldComponentUpdate通过比较状态对象来检查状态是否相同,并防止不必要的渲染。您可以在此处了解更多信息。

其他资源:

  • 不变性的道
  • 不变的数据结构和JavaScript
  • JavaScript的不变性

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

是的,这是正确的。如果您对如何在应用程序中实现此方法感到困惑,我建议您看看redux是如何做到的以熟悉核心概念,这对我有很大帮助。

我喜欢以Redux为例,因为它具有不变性。它具有一个不变的状态树(称为store),其中所有状态更改都是通过调度动作来显式显示的,该动作由化简器处理,该化简器接受前一个状态以及所述动作(一次一个)并返回应用程序的下一个状态。您可以在此处阅读有关其核心原理的更多信息。

egghead.io上有一个很棒的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();

此外,这些视频进一步详细展示了如何实现以下方面的不变性:

  • 数组
  • 对象


 类似资料:
  • 我目前正在研究React JS和React本机框架。在中途,当我读到Facebook的Flux和Redux实现时,我遇到了不变性或不变性JS库。 问题是,为什么不变性如此重要?变异对象有什么错?这不是让事情变得简单吗? 举个例子,让我们考虑一个简单的新闻阅读器应用程序,它的开头屏幕是新闻标题的列表视图。 如果我设置一个对象数组的值,我不能操作它。这就是不可变原则所说的,对吗?(如果我错了请纠正我。

  • 问题内容: 试图弄清楚React的基础知识。 查看此页面上的第二个示例:https : //facebook.github.io/react/ 我看到tick()函数设置Timer类的状态,将前一个值加1。 但是,当我尝试实现自己的简单Counter类时,它失败了,并且出现控制台错误,提示 无法读取未定义的setState属性。 一些谷歌搜索显示我必须将其绑定到增量函数。但是,为什么在我看到的第一

  • 问题内容: 在Java或Android中,有@Override注释。这是什么意思?我发现它是在方法来自子类或继承接口的方法时使用的,我想进一步了解,其他是@SuppressWarnings及其Anonation,如果是的话,java使用了多少注释以及用于什么目的。 问题答案: 这个问题在这里也很简洁地得到了回答: Android@Override用法 这是一个注释,可以用来告诉编译器和IDE,您打

  • 编辑:哎呀,毕竟安装了铬。

  • 问题内容: 示例1中的问题是“ this”引用了全局名称而不是myName对象。 我了解在将this的值设置为特定对象时使用bind()的方法,因此它可以解决示例1中的问题,但是为什么首先会出现此问题?这仅仅是创建Javascript的方式吗? 我还想知道为什么示例3解决了这个问题,以及示例2和示例3之间的区别。 问题答案: 为什么需要JavaScript bind()? 值是决定 如何 一个功能

  • 问题内容: 我可以将数据发送到服务器,但是只有在使用FromBody-Attribute时才可以。 为什么无法使用Post从主体自动读取json数据? 后端Web API 前端angularjs 问题答案: 仅因为某事是POST请求,所以没有明确的规则如何传递参数。POST请求仍可以包含URL中编码的查询参数。方法参数应该是“简单”类型(字符串,整数等)的查询参数。 通常,复杂类型应该是POST表