扩展语法无法按预期与对象数组一起工作

Posted

技术标签:

【中文标题】扩展语法无法按预期与对象数组一起工作【英文标题】:Spread syntax not working as expected with array of objects 【发布时间】:2017-10-12 21:54:31 【问题描述】:

我有一个反应组件,我试图将对象传播到构造函数中的状态中。

constructor() 
    super()

    const shapesArray = [1, 2, 3]

    let renderStates = shapesArray.map((el, i) => 
        return ['shape'+i]: 'black'
    )

    this.state =  ...renderStates 
    console.log(this.state)

我想通过this.state.shape0 访问颜色, 但是当我控制台日志this.state 时,我得到了这个:

而不是Object shape0: "black", shape1: "black", shape2: "black"

我在这里做错了什么?

【问题讨论】:

你没有在数组文字中使用扩展语法???那应该是 ES6 中的语法错误(也许你启用了一些实验性的 babel 东西) 顺便说一句,对于形状集合等索引值,您应该始终使用对象。 您的renderStates 是一个数组。你不应该使用[...renderStates]吗? ... is not an operator! 【参考方案1】:

那是因为你将一个数组传播到一个对象中。数组实际上是(通常)以连续整数 strings 作为键的对象。这些键是数组的索引。

如下图,map 接受一个数组并产生另一个数组

const shapesArray = [1, 2, 3];

const renderStates = shapesArray.map((el, i) => 
  return 
    ['shape' + i]: 'black'
  
);

console.log(renderStates);

当传播到一个对象中时,源对象中每个自己的可枚举属性的值被添加到其各自键下的目标中。由于数组的键是它的索引,因此您最终会得到一个对象,该对象具有数组的每个元素的属性。每个属性的名称是它在数组中的索引。

要实现您想要的,您可以使用Array.prototype.reduce 从数组中构建一个对象,并使用在映射过程中创建的名称。

const shapesArray = [1, 2, 3];

const renderStates = shapesArray
  .map((el, i) => 
    return 
      ['shape' + i]: 'black'
    
  )
  .reduce((o, element) => 
    Object.keys(element).forEach(key => o[key] = element[key]);
    return o;
  , );

console.log(renderStates);

当然,这本身可以通过在reduce内部传播对象来更优雅地编写。

const shapesArray = [1, 2, 3];

const renderStates = shapesArray
  .map((el, i) => 
    return 
      ['shape' + i]: 'black'
    
  )
  .reduce((o, element) => (...o, ...element), );

console.log(renderStates);

【讨论】:

使用 Object.assign 而不是 forEach 循环或非标准语法 完美,谢谢!我在想你可以将renderStates 数组(对象)的值传播到一个对象中,它们的键就是索引。【参考方案2】:

作为对aluan-haddad's answer的优化,reduce可以处理map中的逻辑

const shapesArray = [1, 2, 3];

const renderStates = shapesArray
  .reduce((acc, _, i) => (
    ...acc,
    ['shape' + i]: 'black',
  ), );

console.log(renderStates);

【讨论】:

很好,但是你需要指定3个参数,因为第3个绑定到索引,第二个绑定到元素,第一个绑定到累加器。请注意,乍一看,这看起来是正确的,因为数组包含连续数字,但实际上相差 1。 感谢@AluanHaddad。【参考方案3】:

renderStates 是一个数组,它具有从 0 开始的整数属性 或数组索引(如果您想具体说明),因此...renderStates 将获取每个索引,并从该索引创建映射到与该索引对应的值,要实现您要查找的内容,您需要将 renderStates 数组减少为这样的对象

let renderStates = shapesArray.map((el, i) => 
        return ['shape'+i]: 'black'
    ).reduce((resultObj, currentShape,index) => resultObj['shape'+index] = currentShape['shape'+index]),  );

renderStates现在是一个对象,你可以传播它,它会产生你想要的结果

【讨论】:

【参考方案4】:

无需对数组进行两次迭代。使用减少:

const shapesArray = [1, 2, 3];

const renderStates = shapesArray.reduce((accumulator, i) => 
  accumulator['shape' + i] = 'black';
  return accumulator;
, );

console.log(renderStates);

【讨论】:

以上是关于扩展语法无法按预期与对象数组一起工作的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中对整数数组进行线性搜索时,SSE 比较无法按预期工作

光线投射和二维阵列在 Unity 中的魔方无法按预期工作

javascript typeof null 没有按预期工作

chai 测试数组相等性没有按预期工作

对象数组未按预期运行

React/Redux - 使用扩展运算符将对象添加到数组的开头