如何从键值对数组创建对象?
Posted
技术标签:
【中文标题】如何从键值对数组创建对象?【英文标题】:How to create an object from an Array of key-value pairs? 【发布时间】:2013-12-02 07:46:22 【问题描述】:在 Python 中,可以向 dict
1 构造函数传递一系列键值对:
>>> 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 中的反函数。
【参考方案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 中有 isArray.prototype.forEach
:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 不建议在 JavaScript 中使用 'for .. in' 来遍历数组中的元素:***.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()
方法。您始终可以在以下对象上使用该方法:
这是一个例子:
// 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
【讨论】:
以上是关于如何从键值对数组创建对象?的主要内容,如果未能解决你的问题,请参考以下文章