简体   繁体   English

如何从键值对数组创建对象?

[英]How to create an object from an Array of key-value pairs?

In Python one can pass the dict 1 constructor a sequence of key-value pairs:在 Python 中,可以向dict 1构造函数传递一系列键值对:

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

I can't think of any way to do this sort of thing in JavaScript other than defining my own function for the purpose:除了为此目的定义我自己的函数之外,我想不出在 JavaScript 中做这种事情的任何方法:

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

But I'm a JS noob... Is there anything built-in for this sort pairs-to-object conversion?但我是一个 JS 菜鸟......这种对到对象的转换有什么内置的吗?

1 For the purposes of this question, I'm treating Python dicts as Python's counterpart of JS objects, although, of course the similarity is limited only to the fact that they are both key-value collections. 1就这个问题而言,我将 Python dicts 视为 Python 的 JS 对象的对应物,当然,相似之处仅限于它们都是键值集合这一事实。

Object.fromEntries does the job. Object.fromEntries完成这项工作。 It was added to the language with EcmaScript2019.它是通过 EcmaScript2019 添加到语言中的。

If you don't have support for that function, you could define it yourself with the following ES2015 code:如果您不支持该功能,您可以使用以下 ES2015 代码自行定义:

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

A nice thing is that this method does the opposite of Object.entries (ES2017), so now you can go back and forth between the object and array representation:一件好事是这个方法与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 ES6 地图

There is an alternative to plain objects for key/value pairs: Map .键/值对的普通对象有一个替代方案: Map

Its constructor accepts the array-of-pairs format:它的构造函数接受数组对格式:

 // 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());

If you really need a plain object, then this is not useful, but a Map might present a viable alternative.如果您确实需要一个普通对象,那么这没有用,但 Map 可能会提供一个可行的替代方案。

You can use the reduce function您可以使用减少功能

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

o is now the equivalent of {1:2, 3:4, 5:6} o 现在相当于{1:2, 3:4, 5:6}

If your input array is sparse, you'll want to add a if(curr!=undefined) test on the assignment, but make sure you still return "prev".如果您的输入数组是稀疏的,您需要在分配中添加一个if(curr!=undefined)测试,但请确保您仍然返回“prev”。

If your tuples are something more complex than simple [key,value], you can simply change the way "prev" is assigned to.如果您的元组比简单的 [key,value] 更复杂,您可以简单地更改“prev”的分配方式。 Eg: prev["key-"+curr[0].toString()]=curr[1]*2;例如: prev["key-"+curr[0].toString()]=curr[1]*2;

At the time of writing (2013) JavaScript objects / dictionaries / associative arrays don't have such a constructor natively.在撰写本文时(2013 年),JavaScript 对象/字典/关联数组本身没有这样的构造函数。

As you said yourself, you can of course build your own function using for instance a functional approach using the reduce function as explained in one of the other answers.正如您自己所说,您当然可以使用例如使用reduce函数的函数方法构建自己的函数,如其他答案之一所述。 A classic for or newer forEach loop would also work, of course.当然,经典的 for 或更新的 forEach 循环也可以使用。 But there isn't anything built-in.但是没有内置任何东西。


Edit : It's 2019 and now we have Object.fromEntries , which will give you what you need.编辑:现在是 2019 年,现在我们有了Object.fromEntries ,它将为您提供所需的东西。

Lodash's fromPairs function will do this: Lodash 的fromPairs函数会这样做:

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

Object.fromEntries()

There is a method on the Object object called Object.fromEntries(iterable) . Object对象上有一个名为Object.fromEntries(iterable) The iterator object from the iterable object has to produce an array with 2 elements.来自可迭代对象的迭代器对象必须生成一个包含 2 个元素的数组。 The first (index 0) array element will be the object key and the second the value.第一个(索引 0)数组元素将是对象键,第二个是值。

MDN describes this very accurately: MDN 非常准确地描述了这一点:

The Object.fromEntries() method takes a list of key-value pairs and returns a new object whose properties are given by those entries. Object.fromEntries()方法采用键值对列表并返回一个新对象,其属性由这些条目给出。 The iterable argument is expected to be an object that implements an @@iterator method, that returns an iterator object, that produces a two element array-like object, whose first element is a value that will be used as a property key, and whose second element is the value to associate with that property key. iterable 参数应该是一个实现@@iterator方法的对象,该对象返回一个迭代器对象,该对象产生一个两元素的类数组对象,其第一个元素是一个将用作属性键的值,其第二个元素是与该属性键关联的值。


How to use:如何使用:

You don't even need to know the specifics of an iterable object in order to use the Object.fromEntries() method.为了使用Object.fromEntries()方法,您甚至不需要知道可迭代对象的细节。 You can always use the method on the following objects:您始终可以在以下对象上使用该方法:

  • 2 Dimensional arrays where the inner/nested arrays have 2 elements 2 维数组,其中内部/嵌套数组有 2 个元素
  • Maps地图

Here is an example:下面是一个例子:

 // 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" }

Caveat, browser compatibility!注意,浏览器兼容性!

At the time of this writing (december 2019) this method is relatively new and not implemented by all browsers.在撰写本文时(2019 年 12 月),此方法相对较新,并非所有浏览器都实现。 In order to use this method and to ensure that you JS code will run in all browsers you might have to transpile your code to a earlier version of JS.为了使用此方法并确保您的 JS 代码将在所有浏览器中运行,您可能必须将您的代码转换为早期版本的 JS。

Javascript does not have a native function for converting an array into an object in the way you have described. Javascript 没有以您描述的方式将数组转换为对象的本机函数。 But, this is because there is no need for it.但是,这是因为没有必要。 You have already included in the question an example solution, where you define the function yourself, but that really isn't necessary.您已经在问题中包含了一个示例解决方案,您可以在其中自己定义函数,但这确实没有必要。 As long as you can be sure that the input array is correct, you could even do the conversion with a simple for loop, like so:只要您可以确定输入数组是正确的,您甚至可以使用简单的 for 循环进行转换,如下所示:

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

Which is just about the most basic code imaginable.这只是可以想象的最基本的代码。

Of course, (as mamapitufo points out) it is generally a bad idea to actually use for..in to iterate over an array, because that will also return non-indexes as values of i.当然,(正如 mamapitufo 指出的那样)实际上使用 for..in 来迭代数组通常是一个坏主意,因为这也会返回非索引作为 i 的值。 Still, the point is that this kind of operation is too simple, and too rarely needed, to justify having a native function.尽管如此,关键是这种操作太简单,而且很少需要,无法证明拥有本机功能是合理的。

The python dict is a structure which is not needed in javascript, because the two languages have different approaches to typing, and to design in general, and so what is useful to one is not useful to another. python dict 是一种在 javascript 中不需要的结构,因为这两种语言有不同的打字方法和一般设计方法,因此对一种语言有用的对另一种语言没有用。 While you could work on using the same methods and structures that you used in python, it might be a better idea to think about how to take advantage of javascript's different way of doing things - maybe you will find that you don't need a dict after all.虽然您可以使用在 python 中使用的相同方法和结构,但考虑如何利用 javascript 的不同做事方式可能是一个更好的主意 - 也许您会发现您不需要 dict毕竟。

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)

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

entries.reduce((prev, curr) => Object.assign(prev, { [curr[0]]: curr[1] }), {});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM