【问题标题】:Add key value pair to all objects in array将键值对添加到数组中的所有对象
【发布时间】:2016-10-03 08:10:09
【问题描述】:

我想为数组中的所有对象添加一个 key:value 参数。

例如:

var arrOfObj = [{name: 'eve'},{name:'john'},{name:'jane'}];

现在我想为所有对象添加一个新参数 isActive,以便生成的数组看起来像。

例如:

    [{
    name: 'eve',
    isActive: true
}, {
    name: 'john',
    isActive: true
}, {
    name: 'jane',
    isActive: true
}]

我总是可以遍历数组并插入一个键值对。但是想知道是否有更好的方法来做到这一点

【问题讨论】:

  • arrOfObj.map(o => o.isActive = true;)
  • 更好的是 arrOfObj.map(o => (o.isActive = true));这不会在 ESLint 上引发 no-return-assign 错误,并且也被认为是最佳实践。
  • @SarasArya 感谢。

标签: javascript arrays


【解决方案1】:

map() 函数是这种情况下的最佳选择


tl;dr - 这样做:

const newArr = [
  {name: 'eve'},
  {name: 'john'},
  {name: 'jane'}
].map(v => ({...v, isActive: true}))

map() 函数不会修改初始数组,而是创建一个新数组。 这也是保持初始数组不变的好习惯。


替代方案

const initialArr = [
      {name: 'eve'},
      {name: 'john'},
      {name: 'jane'}
    ]

const newArr1 = initialArr.map(v => ({...v, isActive: true}))
const newArr2 = initialArr.map(v => Object.assign(v, {isActive: true}))

// Results of newArr1 and newArr2 are the same

有条件地添加键值对

const arr = [{value: 1}, {value: 1}, {value: 2}]   
const newArr1 = arr.map(v => ({...v, isActive: v.value > 1}))

如果条件为假,我根本不想添加新字段怎么办?

const arr = [{value: 1}, {value: 1}, {value: 2}]   
const newArr = arr.map(v => {
  return v.value > 1 ? {...v, isActive: true} : v 
})

添加WITH对初始数组的修改

const initialArr = [{a: 1}, {b: 2}]
initialArr.forEach(v => {v.isActive = true;});

这可能不是一个最好的主意,但在现实生活中,有时这是唯一的方法。


问题

  • 我应该使用扩展运算符 (...) 还是 Object.assign,有什么区别?

我个人更喜欢使用扩展运算符,因为我认为它在现代 Web 社区中的使用范围更广(尤其是 React 的开发人员喜欢它)。但是您可以自己检查差异:link(有点固执和陈旧,但仍然)

  • 我可以使用 function 关键字代替 => 吗?

当然可以。粗箭头 (=>) 函数与 this 的作用略有不同,但对于这种特殊情况来说并不那么重要。但是胖箭头的功能更短,有时作为回调更好。因此使用粗箭头函数是更现代的方法。

  • 地图函数内部实际发生了什么:.map(v => ({...v, isActive: true})

Map 函数按数组元素进行迭代,并为每个元素应用回调函数。该回调函数应返回将成为新数组元素的内容。 我们告诉.map() 函数如下:获取当前值(v 这是一个对象),从v 中取出所有键值对并将其放入一个新对象({...v})中,但还要添加属性isActive 并将其设置为 true ({...v, isActive: true}) 然后返回结果。顺便说一句,如果原始对象包含 isActive 归档,它将被覆盖。 Object.assign 的工作方式类似。

  • 我可以一次添加多个字段

是的。

[{value: 1}, {value: 1}, {value: 2}].map(v => ({...v, isActive: true, howAreYou: 'good'}))
  • 我在.map()方法中不应该做的事情

你不应该做任何副作用[link 1link 2],但显然你可以。

还要注意map() 遍历数组的每个元素并为每个元素应用函数。所以如果你在里面做一些沉重的事情,你可能会很慢。这个(有点老套)solution 在某些情况下可能会更有效率(但我认为您一生中不应多次应用它)。

  • 能否将地图的回调提取到单独的函数中?

当然可以。

const arr = [{value: 1}, {value: 1}, {value: 2}]   
const newArr = arr.map(addIsActive)

function addIsActive(v) {
    return {...v, isActive: true}
}
  • 旧的 for 循环有什么问题?

for 没有任何问题,您仍然可以使用它,它只是一种更冗长、更不安全并且会改变初始数组的老式方法。不过你可以试试:

const arr = [{a: 1}, {b: 2}]
for (let i = 0; i < arr.length; i++) {
 arr[i].isActive = true
}
  • 我还应该学习什么

很好地学习以下方法map()filter()reduce()forEach()find() 将是明智之举。这些方法可以解决 80% 的你通常想用数组做的事情。

【讨论】:

  • 在map函数中不需要返回
  • "const initialArr = [ {name: 'eve'}, {name: 'john'}, {name: 'jane'} ] const newArr1 = initialArr.map(v => ({. ..v, isActive: true})) const newArr2 = initialArr.map(v => Object.assign({}, {isActive: true})) // newArr1 和 newArr2 的结果是一样的 " 这部分不对. newArr1 和 newArr2 不相同。请正确回答
【解决方案2】:

您可以通过map() 做到这一点

var arrOfObj = [{
  name: 'eve'
}, {
  name: 'john'
}, {
  name: 'jane'
}];

var result = arrOfObj.map(function(o) {
  o.isActive = true;
  return o;
})

console.log(result)

如果您想保留原始数组,可以使用 Object.assign() 克隆对象

var arrOfObj = [{
  name: 'eve'
}, {
  name: 'john'
}, {
  name: 'jane'
}];

var result = arrOfObj.map(function(el) {
  var o = Object.assign({}, el);
  o.isActive = true;
  return o;
})

console.log(arrOfObj);
console.log(result);

【讨论】:

  • 不需要退货
  • @splay...在这种情况下是这样,因为 map 的结果被分配给了 result 变量。更明显的是 map 返回一个新数组(而不是将其用作每个数组的丢弃)
  • 地图不是在后台循环遍历数组吗?
【解决方案3】:

我会对这里提供的一些答案有点谨慎,以下示例根据方法输出不同:

const list = [ { a : 'a', b : 'b' } , { a : 'a2' , b : 'b2' }]

console.log(list.map(item => item.c = 'c'))
// [ 'c', 'c' ]

console.log(list.map(item => {item.c = 'c'; return item;}))
// [ { a: 'a', b: 'b', c: 'c' }, { a: 'a2', b: 'b2', c: 'c' } ]

console.log(list.map(item => Object.assign({}, item, { c : 'c'})))
// [ { a: 'a', b: 'b', c: 'c' }, { a: 'a2', b: 'b2', c: 'c' } ]

我已经用node v8.10.0测试了上面的几段代码。

【讨论】:

  • 如今,有了 node v8+ 带来的所有新功能,使用 Object.assign 是一个非常好的和优雅的选择。
【解决方案4】:

你也可以试试这个:

arrOfObj.forEach(function(item){item.isActive = true;});

console.log(arrOfObj);

【讨论】:

    【解决方案5】:

    @Redu 的解决方案不错

    arrOfObj.map(o => o.isActive = true;) 但 Array.map 仍然算作循环遍历所有项目。

    如果你绝对不想有任何循环,这是一个肮脏的黑客:

    Object.defineProperty(Object.prototype, "isActive",{
      value: true,
      writable: true,
      configurable: true,
      enumerable: true
    });
    

    我的建议是不要小心使用它, 它绝对会修补所有 javascript 对象(日期、数组、数字、字符串或任何其他继承 Object 的对象),这是非常糟糕的做法......

    【讨论】:

    • o.isActive = true 应该是 o.isActive == true 或只是 o.isActive
    【解决方案6】:
    arrOfObj.map(o => { 
      o.isActive = true; 
      return o; 
    });
    

    【讨论】:

    • 这需要返回新的objoarrOfObj.map(o =&gt; (o.isActive = true)); =&gt; [true, true, true]应该写成:arrOfObj.map(o =&gt; { o.isActive = true; return o; });
    【解决方案7】:
    _.forEach(arrOfObj,(arrVal,arrIn) => {
                 arrVal.isAcitve = true;
                }
    

    【讨论】:

      【解决方案8】:

      遍历数组并插入键值对是您的最佳解决方案。您可以使用“地图”功能,但这只是一个偏好问题。

      var arrOfObj = [{name: 'eve'},{name:'john'},{name:'jane'}];
      arrOfObj.map(function (obj) { 
         obj.isActive = true;
      });
      

      【讨论】:

        【解决方案9】:

        只需使用map函数:

        var arrOfObj = arrOfObj.map(function(element){
           element.active = true;
           return element;
        }
        

        Map 在兼容性方面相当不错:您可以在 IE

        但是,如果您 100% 确定您的用户将使用 ES6 兼容浏览器,您可以使用arrow functions 缩短该功能,正如@Sergey Panfilov 所建议的那样。

        【讨论】:

        • 不需要返回
        • @splay 如果你想正确使用.map()。如果您只想将其用作循环,则应该使用.forEach()
        【解决方案10】:
            var arrOfObj = [{name: 'eve'},{name:'john'},{name:'jane'}];
            var injectObj = {isActive:true, timestamp:new Date()};
        
            // function to inject key values in all object of json array
        
            function injectKeyValueInArray (array, keyValues){
                return new Promise((resolve, reject) => {
                    if (!array.length)
                        return resolve(array);
        
                    array.forEach((object) => {
                        for (let key in keyValues) {
                            object[key] = keyValues[key]
                        }
                    });
                    resolve(array);
                })
            };
        
        //call function to inject json key value in all array object
            injectKeyValueInArray(arrOfObj,injectObj).then((newArrOfObj)=>{
                console.log(newArrOfObj);
            });
        

        输出如下:-

        [ { name: 'eve',
            isActive: true,
            timestamp: 2017-12-16T16:03:53.083Z },
          { name: 'john',
            isActive: true,
            timestamp: 2017-12-16T16:03:53.083Z },
          { name: 'jane',
            isActive: true,
            timestamp: 2017-12-16T16:03:53.083Z } ]
        

        【讨论】:

          【解决方案11】:
          let arrOfObj = [{name: 'eve'},{name:'john'},{name:'jane'}];
          let newArr = arrOfObj.map(i => ({...i,isActive: true}));
          

          我在这里所做的是传播当前对象并向对象插入一个带有值的新键并将其作为新对象返回。

          【讨论】:

          • 发布答案时,最好检查现有答案并使您的答案独一无二。
          【解决方案12】:

          var arrOfObj = [{name: 'eve'},{name:'john'},{name:'jane'}];
          const result = arrOfObj.map((name) => {
              name["isActive"] = true;
              return name;
          });
          console.log(result);

          【讨论】:

          • 感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。 proper explanation 将通过展示为什么这是解决问题的好方法,并使其对有其他类似问题的未来读者更有用,从而大大提高其长期价值。请edit您的回答添加一些解释,包括您所做的假设。
          猜你喜欢
          • 2019-07-03
          • 1970-01-01
          • 2022-06-29
          • 2014-07-09
          • 1970-01-01
          • 2022-12-28
          • 2022-06-10
          • 2016-07-18
          • 1970-01-01
          相关资源
          最近更新 更多