更改数组项的最佳方法是什么?
What is the best way to change items of an array?
在 Redux 中更改存储数组元素的最佳方法是什么?我有这 3 个工作 solutions.which 是最好的一个?我认为前两个解决方案正在改变状态。是真的吗?
如果您有更好的解决方案,我将不胜感激。
在这个例子中,我有一个订单列表,我想增加列表中一个订单的数量。我将此订单索引作为 orderIndex in action 传递。
第一种方式:
let order = state[action.orderIndex];
order.quantity++;
return Object.assign([],order);
第二种方式:
let order= Object.assign([],state);
order[action.orderIndex].quantity++;
return Object.assign([],order);
第三种方式:
return Object.assign([],state.map(
(order,index) => (index==action.orderIndex) ? {...order,quantity:order.quantity+1} : order)
);
我有另一个解决方案,但它 return 是一个对象,我不知道如何在此解决方案中 return 一个数组。 :
return {...state,[action.orderIndex]:{...state[action.orderIndex],quantity:state[action.orderIndex].quantity+1}};
如果您要修改数组中的项目,请使用新值创建一个新项目,然后 return 一个新数组,将您要修改的项目之前和之后的元素切片并将其插入中间。使用 ES6 传播语法,您可以执行以下操作:
var newArray = [
...originalArray.slice(0, indexOfAmendedItem),
amendedItem,
...originalArray.slice(indexOfAmendedItem + 1)
];
看这个:
https://egghead.io/lessons/javascript-redux-avoiding-array-mutations-with-concat-slice-and-spread
它解释得很好。
第一个修改原来的顺序是一个突变。这违反了 Redux 存储的不变性。
第二种复制了数组,但是数组里面的对象还是原来的命令。它们只是引用与原始数组相同的实例。因此,当您在下一行修改其中一个时,您正在改变 Redux 状态。
第三种方式很有趣,因为即使你没有改变状态,它也可以被简化。
return state.map(order => (index==action.orderIndex) ? {...order, quantity: order.quantity+1} : order);
因为map
函数已经returns了一个新数组,所以没必要调用Object.assign
.
第三个版本之所以有效,是因为您引用了 所有您未修改的订单,并且仅为您要更改的一项创建了新订单。由于不允许突变,您需要创建一个新对象。
现在,ES6 语法可能会令人困惑。你可以让它在没有 ES6 的情况下完全工作(Object.assign
除外,但你可以用下划线中的 extend
替换它。重要的是没有使用新语法)。
// copy the list so we can modify the copy without mutating the original
// it is important to realize that even though the list is brand new
// the items inside are still the original orders
var newOrders = state.slice();
// grab the old order we'd like to modify
// note that we could have grabbed it from state as well
// they are one and the same object
var oldOrder = newOrders[action.orderIndex];
// this takes a new object and copies all properties of oldOrder into it
// it then copies all properties of the final object into it
// the final object has only our new property
// we could have multiple properties there if we needed
var newOrder = Object.assign({}, oldOrder, { quantity: oldOrder.quantity + 1 });
// now we just replace the old order with the new one
// remember it's okay to modify the list since we copied it first
newOrders[action.orderIndex] = newOrder;
return newOrders;
或者,您可以直接修改副本,如下所示:
var newOrders = state.slice();
var oldOrder = newOrders[action.orderIndex];
// make a shallow copy
var newOrder = Object.assign({}, oldOrder);
// we can now modify immediate properties of the copy
newOrder.quantity++;
newOrders[action.orderIndex] = newOrder;
return newOrders;
这两种做事方式的区别在于,使用map
的版本(以及更多的ES6重载版本)是一个单一的表达式。这使它更实用。您无需指定获得结果的步骤,而是指定结果应该是什么样子。它是声明式还是命令式。
声明式版本有时更清晰。再说一次,通常情况并非如此。它 通常较短,但看起来很陌生。如果您来自功能世界,那么它看起来和感觉起来完全正常。外星人从不认为自己是外星人。
我认为易于理解比更短的代码更重要。请注意,它不太可能更快。例如,map
版本会为每个订单调用您的函数。
如果您有数百万个订单(正如我们都希望得到的那样),我们最终会检查每个订单以确定它是否是我们要修改的订单。
但是,当使用命令式版本时,您会复制数组,在该操作期间我们不会检查任何命令。它非常快,比 map
版本快得多。
那么为什么我们看到人们使用 map
呢?好吧,如果您只有几个订单,性能就不是问题,而且对于那里的功能纯粹主义者来说,它看起来不错。
还有 Mark 对 ES6 做事方式的回答。它通过复制要替换的项目之前的部分来创建一个新数组,添加新项目,然后在要替换的项目之后添加该部分。这很快。它也很丑(在我看来)。
当然,你想一想它的作用就很清楚了。它取代了我们需要更换的一件物品。但是,它读起来不像是替代品。事实上,索引中唯一未提及的项目是我们要替换的项目。
我想说的是,除非你试图证明你的整个应用程序可以只是一个单一的巨大表达式,否则编写命令式代码是完全可以的。如果它更容易理解或编写,那么没有理由不这样做。
在 Redux 中更改存储数组元素的最佳方法是什么?我有这 3 个工作 solutions.which 是最好的一个?我认为前两个解决方案正在改变状态。是真的吗? 如果您有更好的解决方案,我将不胜感激。
在这个例子中,我有一个订单列表,我想增加列表中一个订单的数量。我将此订单索引作为 orderIndex in action 传递。
第一种方式:
let order = state[action.orderIndex];
order.quantity++;
return Object.assign([],order);
第二种方式:
let order= Object.assign([],state);
order[action.orderIndex].quantity++;
return Object.assign([],order);
第三种方式:
return Object.assign([],state.map(
(order,index) => (index==action.orderIndex) ? {...order,quantity:order.quantity+1} : order)
);
我有另一个解决方案,但它 return 是一个对象,我不知道如何在此解决方案中 return 一个数组。 :
return {...state,[action.orderIndex]:{...state[action.orderIndex],quantity:state[action.orderIndex].quantity+1}};
如果您要修改数组中的项目,请使用新值创建一个新项目,然后 return 一个新数组,将您要修改的项目之前和之后的元素切片并将其插入中间。使用 ES6 传播语法,您可以执行以下操作:
var newArray = [
...originalArray.slice(0, indexOfAmendedItem),
amendedItem,
...originalArray.slice(indexOfAmendedItem + 1)
];
看这个:
https://egghead.io/lessons/javascript-redux-avoiding-array-mutations-with-concat-slice-and-spread
它解释得很好。
第一个修改原来的顺序是一个突变。这违反了 Redux 存储的不变性。
第二种复制了数组,但是数组里面的对象还是原来的命令。它们只是引用与原始数组相同的实例。因此,当您在下一行修改其中一个时,您正在改变 Redux 状态。
第三种方式很有趣,因为即使你没有改变状态,它也可以被简化。
return state.map(order => (index==action.orderIndex) ? {...order, quantity: order.quantity+1} : order);
因为map
函数已经returns了一个新数组,所以没必要调用Object.assign
.
第三个版本之所以有效,是因为您引用了 所有您未修改的订单,并且仅为您要更改的一项创建了新订单。由于不允许突变,您需要创建一个新对象。
现在,ES6 语法可能会令人困惑。你可以让它在没有 ES6 的情况下完全工作(Object.assign
除外,但你可以用下划线中的 extend
替换它。重要的是没有使用新语法)。
// copy the list so we can modify the copy without mutating the original
// it is important to realize that even though the list is brand new
// the items inside are still the original orders
var newOrders = state.slice();
// grab the old order we'd like to modify
// note that we could have grabbed it from state as well
// they are one and the same object
var oldOrder = newOrders[action.orderIndex];
// this takes a new object and copies all properties of oldOrder into it
// it then copies all properties of the final object into it
// the final object has only our new property
// we could have multiple properties there if we needed
var newOrder = Object.assign({}, oldOrder, { quantity: oldOrder.quantity + 1 });
// now we just replace the old order with the new one
// remember it's okay to modify the list since we copied it first
newOrders[action.orderIndex] = newOrder;
return newOrders;
或者,您可以直接修改副本,如下所示:
var newOrders = state.slice();
var oldOrder = newOrders[action.orderIndex];
// make a shallow copy
var newOrder = Object.assign({}, oldOrder);
// we can now modify immediate properties of the copy
newOrder.quantity++;
newOrders[action.orderIndex] = newOrder;
return newOrders;
这两种做事方式的区别在于,使用map
的版本(以及更多的ES6重载版本)是一个单一的表达式。这使它更实用。您无需指定获得结果的步骤,而是指定结果应该是什么样子。它是声明式还是命令式。
声明式版本有时更清晰。再说一次,通常情况并非如此。它 通常较短,但看起来很陌生。如果您来自功能世界,那么它看起来和感觉起来完全正常。外星人从不认为自己是外星人。
我认为易于理解比更短的代码更重要。请注意,它不太可能更快。例如,map
版本会为每个订单调用您的函数。
如果您有数百万个订单(正如我们都希望得到的那样),我们最终会检查每个订单以确定它是否是我们要修改的订单。
但是,当使用命令式版本时,您会复制数组,在该操作期间我们不会检查任何命令。它非常快,比 map
版本快得多。
那么为什么我们看到人们使用 map
呢?好吧,如果您只有几个订单,性能就不是问题,而且对于那里的功能纯粹主义者来说,它看起来不错。
还有 Mark 对 ES6 做事方式的回答。它通过复制要替换的项目之前的部分来创建一个新数组,添加新项目,然后在要替换的项目之后添加该部分。这很快。它也很丑(在我看来)。
当然,你想一想它的作用就很清楚了。它取代了我们需要更换的一件物品。但是,它读起来不像是替代品。事实上,索引中唯一未提及的项目是我们要替换的项目。
我想说的是,除非你试图证明你的整个应用程序可以只是一个单一的巨大表达式,否则编写命令式代码是完全可以的。如果它更容易理解或编写,那么没有理由不这样做。