使用扩展和解构运算符修改不可变对象的最短方法是啥

Posted

技术标签:

【中文标题】使用扩展和解构运算符修改不可变对象的最短方法是啥【英文标题】:What is the shortest way to modify immutable objects using spread and destructuring operators使用扩展和解构运算符修改不可变对象的最短方法是什么 【发布时间】:2016-08-01 21:02:46 【问题描述】:

我正在寻找一个纯函数来修改我的不可变状态对象。作为参数给出的原始状态必须保持不变。这在使用像Redux 这样的框架时特别有用,并且使在javascript 中使用immutable 对象变得更加容易。尤其是使用 Babel 处理对象扩展运算符已经成为可能。

我没有找到比先复制对象更好的方法,然后像这样分配/删除我想要的属性:

function updateState(state, item) 
  newState = ...state;
  newState[item.id] = item;
  return newState;


function deleteProperty(state, id) 
    var newState = ...state;
    delete newState[id];
    return newState;

我觉得它可以更短

【问题讨论】:

【参考方案1】:

对状态的操作,其中状态被认为是不可变的。

添加或更新属性值

// ES6:
function updateState(state, item) 
    return Object.assign(, state, [item.id]: item);


// With Object Spread:
function updateState(state, item) 
  return 
     ...state,
     [item.id]: item
  ;

删除属性

// ES6:
function deleteProperty(state, id) 
    var newState = Object.assign(, state);
    delete newState[id];
    return newState; 


// With Object Spread:
function deleteProperty(state, id) 
    let  [id]: deleted, ...newState = state;
    return newState;


// Or even shorter as helper function:
function deleteProperty([id]: deleted, ...newState, id) 
    return newState;


// Or inline:
function deleteProperty(state, id) 
    return (([id]: deleted, ...newState) => newState)(state);

【讨论】:

提问后几秒钟就回答自己的问题?!​​ 我使用问题表单下方的字段来回答它,因为我在发布问题之前找到了解决方案。由于谷歌搜索非常困难,所以我把它放在这里给大家。 但实际上,删除属性也是一个有趣的问题。由于将属性设置为未定义,不会删除键,并且删除似乎在对象定义中不起作用;) 你声称是 ES7 的不是 ES7。对象传播和休息仍然是一个提议。它可能会出现在 ES2017 中。 我希望我能更多地投票给这个。我已经多次回到这个帖子XD【参考方案2】:

一个有更多支持的 ES6 解决方案是 Object.assign:

const updateState = (state, item) => Object.assign(, state,  [item.id]: item );

【讨论】:

当然,在 ES5 风格中也是如此。 抱歉必须更新问题。为此使用 babel es6 + 插件 ;) 有点困惑。 其实箭头函数只有ES6才有,所以这个sn-p就是ES6。【参考方案3】:

在地图函数中

要在映射函数中执行此过程(删除一个属性并在每个对象上添加一个新属性),给定一个对象数组 -

const myArrayOfObjects = [
    id: 1, keyToDelete: 'nonsense',
    id: 2, keyToDelete: 'rubbish'
];

删除属性keyToDelete,并添加一个值为"someVar"的新键newKey

myArrayOfObjects.map(( keyToDelete, ...item) =>  ...item, newKey:'someVar');

将数组更新为

[
    id: 1, newKey:'someVar',
    id: 2, newKey:'someVar'
]

有关删除方法的更多信息,请参阅this great post。

【讨论】:

【参考方案4】:

除了编写难以阅读的样板代码(如上面的回答:(([id]: deleted, ...state) => state)(state)),您可以使用一些库来做同样的事情:

https://github.com/cah4a/immutable-modify https://github.com/kolodny/immutability-helper https://github.com/M6Web/immutable-set https://github.com/bormind/immutable-setter

例如:

import remove from 'immutable-modify'

function updateState(state, item) 
   return remove(state, item.id)

它还支持任何嵌套更新:

import set from 'immutable-modify'

function updateState(state, item) 
   return set(state, 'user.products', (products) => (
      ...products,
      items: products.items.concat(item),
      lastUpdate: Date.now()
   ))

【讨论】:

【参考方案5】:

试试:

const  id, ...noId  = state;

并测试:

console.log(noId);

【讨论】:

【参考方案6】:

从数组中删除项目,只需使用过滤器;)

CASE 'REMOVE_ITEM_SUCCESS':

      let items = state.items.filter(element => element._id !== action.id);

      return 
            ...state, 
            items
      

【讨论】:

以上是关于使用扩展和解构运算符修改不可变对象的最短方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

在 JavaScript 中仅复制选定属性的最短方法是啥?

使用 jQuery 创建帖子表单并提交它的最短方法是啥? [复制]

在java中初始化字符串列表的最短方法是啥?

Python基础_列表元祖和字典

使用 std::ostream 打印可变参数包的最简单方法是啥?

获取周围坐标的最短代码是啥?