对象(而不是数组)的 map 函数
我有一个对象:
myObject = { 'a': 1, 'b': 2, 'c': 3 }
我正在寻找一种类似于
Array.prototype.map
的本机方法,其用法如下:
newObject = myObject.map(function (value, label) {
return value * value;
});
// newObject is now { 'a': 1, 'b': 4, 'c': 9 }
JavaScript 是否有针对对象的此类
map
函数?(我希望 Node.JS 有这个函数,因此我不关心跨浏览器问题。)
没有原生
map
到
Object
对象,但是这个怎么样:
var myObject = { 'a': 1, 'b': 2, 'c': 3 };
Object.keys(myObject).forEach(function(key, index) {
myObject[key] *= 2;
});
console.log(myObject);
// => { 'a': 2, 'b': 4, 'c': 6 }
但是你可以使用
for ... in
轻松地迭代对象:
var myObject = { 'a': 1, 'b': 2, 'c': 3 };
for (var key in myObject) {
if (myObject.hasOwnProperty(key)) {
myObject[key] *= 2;
}
}
console.log(myObject);
// { 'a': 2, 'b': 4, 'c': 6 }
更新
很多人提到,以前的方法不返回新对象,而是对对象本身进行操作。就此而言,我想添加另一个解决方案,它返回一个新对象并保持原始对象原样:
var myObject = { 'a': 1, 'b': 2, 'c': 3 };
// returns a new object with the values at each key mapped using mapFn(value)
function objectMap(object, mapFn) {
return Object.keys(object).reduce(function(result, key) {
result[key] = mapFn(object[key])
return result
}, {})
}
var newObject = objectMap(myObject, function(value) {
return value * 2
})
console.log(newObject);
// => { 'a': 2, 'b': 4, 'c': 6 }
console.log(myObject);
// => { 'a': 1, 'b': 2, 'c': 3 }
Array.prototype.reduce
通过将前一个值与当前值进行某种合并,将数组简化为单个值。该链由一个空对象
{
初始化。每次迭代时,都会添加一个新键
myObject
,其值是键的两倍。
更新
借助新的 ES6 功能,有一种更优雅的方式来表达
objectMap
。
const objectMap = (obj, fn) =>
Object.fromEntries(
Object.entries(obj).map(
([k, v], i) => [k, fn(v, k, i)]
)
)
const myObject = { a: 1, b: 2, c: 3 }
console.log(objectMap(myObject, v => 2 * v))
在 JS ES10 / ES2019 中使用一行代码怎么样?
利用
Object.entries()
和
Object.fromEntries()
:
let newObj = Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, v * v]));
以函数形式编写的相同内容:
function objMap(obj, func) {
return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, func(v)]));
}
// To square each value you can call it like this:
let mappedObj = objMap(obj, (x) => x * x);
此函数使用 递归 将嵌套对象平方为好吧:
function objMap(obj, func) {
return Object.fromEntries(
Object.entries(obj).map(([k, v]) =>
[k, v === Object(v) ? objMap(v, func) : func(v)]
)
);
}
// To square each value you can call it like this:
let mappedObj = objMap(obj, (x) => x * x);
使用
ES7 / ES2016
,您无法使用
Objects.fromEntries
,但您可以使用
Object.assign
结合
扩展运算符
和
计算键名
语法来实现相同的效果:
let newObj = Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v})));
ES6 / ES2015
不允许使用
Object.entries
,但你可以改用
Object.keys
:
let newObj = Object.assign({}, ...Object.keys(obj).map(k => ({[k]: obj[k] * obj[k]})));
ES6 还引入了
for...of
循环,允许使用更
命令式
的样式:
let newObj = {}
for (let [k, v] of Object.entries(obj)) {
newObj[k] = v * v;
}
array.reduce()
而不是
Object.fromEntries
和
Object.assign
您还可以使用
reduce
来实现此目的:
let newObj = Object.entries(obj).reduce((p, [k, v]) => ({ ...p, [k]: v * v }), {});
继承属性和原型链:
在某些罕见情况下,您可能需要映射一个
类
对象,该对象在其
原型链
上保存继承对象的属性。在这种情况下,
Object.keys()
和
Object.entries()
将不起作用,因为这些函数不包含原型链。
如果您需要映射
继承
的属性,您可以使用
for (key in myObj) {...
。
下面是这种情况的一个例子:
const obj1 = { 'a': 1, 'b': 2, 'c': 3}
const obj2 = Object.create(obj1); // One of multiple ways to inherit an object in JS.
// Here you see how the properties of obj1 sit on the 'prototype' of obj2
console.log(obj2) // Prints: obj2.__proto__ = { 'a': 1, 'b': 2, 'c': 3}
console.log(Object.keys(obj2)); // Prints: an empty Array.
console.log(Object.entries(obj2)); // Prints: an empty Array.
for (let key in obj2) {
console.log(key); // Prints: 'a', 'b', 'c'
}
但是,请帮我一个忙,避免 继承 。:-)
没有原生方法,但 lodash#mapValues 可以出色地完成这项工作
_.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
// → { 'a': 3, 'b': 6, 'c': 9 }