【问题标题】:How to create an object from an Array of key-value pairs?如何从键值对数组创建对象?
【发布时间】:2013-12-02 07:46:22
【问题描述】:

在 Python 中,可以向 dict1 构造函数传递一系列键值对:

>>> dict([['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']])
{'age': 42, 'name': 'Bob', 'breakfast': 'eggs'}

除了为此目的定义我自己的函数之外,我想不出任何办法在 JavaScript 中做这种事情:

function pairs_to_object(pairs) {
    var ret = {};
    pairs.forEach(function (p) { ret[p[0]] = p[1]; });
    return ret;
}

但我是一个 JS 菜鸟......这种排序对到对象的转换有什么内置的吗?

1 出于这个问题的目的,我将 Python dicts 视为 Python 的 JS 对象对应物,尽管相似之处当然仅限于它们都是键值集合。

【问题讨论】:

  • “这种排序对到对象的转换是否有内置的东西?” 不是纯 JavaScript。
  • 一些图书馆提供它:underscorejs.org/#object
  • 有一个 ES proposal 将其添加到 JS 为 Object.fromEntries
  • 这是 Object.entries 函数在 ES2017 中添加到 JS 中的反函数。

标签: javascript


【解决方案1】:

在撰写本文时 (2013),JavaScript 对象/字典/关联数组本身没有这样的构造函数。

正如您自己所说,您当然可以使用例如使用 reduce 函数的函数方法构建自己的函数,如其他答案之一中所述。当然,经典的 for 或更新的 forEach 循环也可以工作。但是没有任何内置的东西。


编辑:现在是 2019 年,现在我们有 Object.fromEntries,它将为您提供所需的一切。

【讨论】:

    【解决方案2】:

    Javascript 没有按照您描述的方式将数组转换为对象的本机函数。但是,这是因为不需要它。您已经在问题中包含了一个示例解决方案,您可以在其中自己定义函数,但这实际上不是必需的。只要您可以确定输入数组是正确的,您甚至可以使用简单的 for 循环进行转换,如下所示:

    var input = [['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']];
    var output = {};
    for(i in input) output[input[i][0]] = input[i][1];
    

    这只是可以想象的最基本的代码。

    当然,(正如 mamapitufo 指出的那样)实际使用 for..in 遍历数组通常是一个坏主意,因为这也会返回非索引作为 i 的值。不过,关键是这种操作过于简单,而且很少需要,不足以证明拥有原生函数是合理的。

    python dict 是 javascript 中不需要的结构,因为这两种语言在输入和设计方面有不同的方法,所以对一个有用的对另一个没有用。虽然您可以使用在 python 中使用的相同方法和结构,但考虑如何利用 javascript 的不同做事方式可能是一个更好的主意 - 也许您会发现您不需要 dict毕竟。

    【讨论】:

    • 在 ES5 中有 is Array.prototype.forEachdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 不建议在 JavaScript 中使用 'for .. in' 来遍历数组中的元素:stackoverflow.com/a/500531/421089
    • @mamapitufo 你是完全正确的,谢谢,我已经编辑了答案以澄清我想说的。
    • > python dict是javascript中不需要的结构 真的吗?所以,目前我有一个键值对列表。我有一个 中每个
    • @Lucretiel 在 javascript 中执行此操作的方法通常是使用对象,因为 javascript 中的数组非常有限,并且不能关联。 Javascript 不需要显式的字典类,因为所有对象本身都是字典。它们也可以是类、函数和原语,有时同时是所有这些——我承认这可能会让人很困惑,但一旦你弄清楚了,它们就会非常灵活。
    【解决方案3】:

    你可以使用reduce函数

    x = [[1,2],[3,4],[5,6]];
    o = x.reduce(function(prev,curr){prev[curr[0]]=curr[1];return prev;},{})
    

    o 现在相当于{1:2, 3:4, 5:6}

    如果您的输入数组是稀疏的,您需要在分配上添加一个if(curr!=undefined) 测试,但请确保您仍然返回“prev”。

    如果您的元组比简单的 [key,value] 更复杂,您可以简单地更改“prev”的分配方式。例如:prev["key-"+curr[0].toString()]=curr[1]*2;

    【讨论】:

    • 这是最好的答案,因为它适用于所有浏览器,并且非常紧凑。每个人都应该学习 map、filter 和 reduce。我花了一段时间才找到结尾的 {},它为 reduce 提供了初始值。此外,粗箭头语法会使其更具可读性,但不适用于所有浏览器。
    【解决方案4】:

    Object.fromEntries 完成这项工作。它是通过 EcmaScript2019 添加到语言中的。

    如果您不支持该功能,您可以使用以下 ES2015 代码自行定义:

    Object.fromEntries = arr => Object.assign({}, ...Array.from(arr, ([k, v]) => ({[k]: v}) ));
    

    好消息是这个方法与Object.entries(ES2017)相反,所以现在你可以在对象和数组表示之间来回切换:

    const arr = [['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']];
    const obj = Object.fromEntries(arr);
    console.log(obj);
    // ... and back:
    const arr2 = Object.entries(obj);
    console.log(arr2); // copy of the original array (omitting duplicate keys)
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    ES6 地图

    对于键/值对,有一个普通对象的替代方案:Map

    它的构造函数接受数组对格式:

    // Demo:
    const arr = [['name', 'Bob'], ['age', 42], ['breakfast', 'eggs']];
    
    const mp = new Map(arr);
    
    // Get one particular value:
    console.log(mp.get('age'));
    // Get all the keys:
    console.log(...mp.keys());
    // Get all the values:
    console.log(...mp.values());
    // Get all the key/value pairs:
    console.log(...mp.entries());

    如果你真的需要一个普通的对象,那么这没什么用,但 Map 可能是一个可行的替代方案。

    【讨论】:

    • 不幸的是,如果要将 Map 序列化为 JSON,则需要额外的工作。否则你的解决方案很酷! +1
    • 谢谢@Kostanos。幸运的是,我的答案的主要 (Object.assign) 部分可用于生成 JSON ;-) 映射具有其他特性(如方便的构造函数,保持插入顺序,允许非字符串作为键,提供 size 属性, ...) 在某些用例中可能很有趣。
    • 这太棒了!谢谢!我对如何/为什么使用方括号作为键(即{[k]: v})有点困惑。这是破坏性的东西吗?我一直在努力想弄清楚如何以这种方式使用变量作为键,当我看到这有效时,我很困惑,但仍然很高兴。
    • 我会继续自己回答这个问题...不,不完全是...任何好奇的人都可以查看这篇文章:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…。相关位是:“从 ECMAScript 2015 开始,对象初始化器语法也支持计算属性名称。这允许您将表达式放在括号 [] 中,它将被计算并用作属性名称。”我非常喜欢 ES20xx...
    • 2018 ES草案中,可以使用object spread syntax代替Object.assign,如下:<array>.reduce((o, [k, v]) => ({...o, [k]: v}), {})
    【解决方案5】:

    Lodash 的 fromPairs 函数会这样做:

    const _ = require('lodash')
    const kvPairs = [['a', 1], ['b', 2]]
    _.fromPairs(kvPairs)
    // => { a: 1, b: 2 }
    

    【讨论】:

      【解决方案6】:

      Object.fromEntries()

      Object 对象上有一个名为Object.fromEntries(iterable) 的方法。来自可迭代对象的迭代器对象必须生成一个包含 2 个元素的数组。第一个(索引 0)数组元素将是对象键,第二个是值。

      MDN 非常准确地描述了这一点:

      Object.fromEntries() 方法采用键值对列表和 返回一个新对象,其属性由这些条目给出。这 可迭代参数应该是一个实现 @@iterator 方法,它返回一个迭代器对象,它产生一个 二元素数组类对象,其第一个元素是一个值 将用作属性键,其第二个元素是值 与该属性键关联。


      使用方法:

      您甚至不需要知道可迭代对象的细节就可以使用Object.fromEntries() 方法。您始终可以在以下对象上使用该方法:

      • 内部/嵌套数组有 2 个元素的 2 维数组
      • 地图

      这是一个例子:

      // map example:
      const map = new Map([ ['hi', 'there'], ['foo', 2] ]);
      const objFromMap = Object.fromEntries(map);
      console.log(objFromMap); // { hi: "there", foo: 2 }
      
      // array example:
      const array = [ ['0', '00'], ['1', '11'], ['2', '22'] ];
      const objFromArray = Object.fromEntries(array);
      console.log(objFromArray); // { 0: "00", 1: "11", 2: "22" }

      注意,浏览器兼容性!

      在撰写本文时(2019 年 12 月),此方法相对较新,并非所有浏览器都实现。为了使用此方法并确保您的 JS 代码可以在所有浏览器中运行,您可能必须将您的代码转换为早期版本的 JS。

      【讨论】:

      • 像这样,但让我们给它一些时间:)
      【解决方案7】:
      const sampleArr = ['foo', 'bar', 'baz', 42];
      const _chunk = (arr, chunkSize, chunks = []) => {
        while (arr.length) {
          chunks = [...chunks, arr.splice(0, chunkSize)];
        }
        return chunks;
      }; //splice array to chunks
      
      const arr = _chunk(sampleArr, 2);
      const entries = new Map([...arr]);
      
      const obj = Object.fromEntries(entries);
      
      console.log(obj)
      

      // 预期输出:Object { foo: "bar", baz: 42 }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-22
        • 2016-12-31
        • 2017-07-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多