对象(而不是数组)的映射函数

map function for objects (instead of arrays)

提问人:Randomblue 提问时间:2/11/2013 最后编辑:Will NessRandomblue 更新时间:9/27/2023 访问量:2689400

问:

我有一个对象:

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 对对象有这样的函数吗?(我想要这个用于 Node.JS,所以我不关心跨浏览器问题。map

JavaScript 节点.js 编程 映射函数

评论

1赞 Oriol 8/10/2016
大多数答案使用 ,它没有任何明确定义的顺序。这可能会有问题,我建议改用。Object.keysObject.getOwnPropertyNames
3赞 Bart 8/15/2017
@Oriol你确定吗?根据 MDN Web 文档,数组元素的顺序在 和 之间是一致的。请参阅 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...Object.keysObject.getOwnPropertyNames
0赞 Oriol 4/3/2018
@Bart 的顺序取决于实现。查看 stackoverflow.com/a/30919039/1529630Object.keys
24赞 B T 8/24/2018
@Oriol 无论如何,你都不应该依赖对象中键的顺序,所以这与这个问题有点无关——因为他从未指定过顺序对他很重要。如果秩序对他来说很重要,他无论如何都不应该使用一个物体。
0赞 masterxilo 11/20/2019
有人请把其中一些解决方案放在 npm 包中,并请进行测试

答:

6赞 whitneyit 2/11/2013 #1

上不存在,但是您可以像这样模拟它map functionObject.prototype

var myMap = function ( obj, callback ) {

    var result = {};

    for ( var key in obj ) {
        if ( Object.prototype.hasOwnProperty.call( obj, key ) ) {
            if ( typeof callback === 'function' ) {
                result[ key ] = callback.call( obj, obj[ key ], key, obj );
            }
        }
    }

    return result;

};

var myObject = { 'a': 1, 'b': 2, 'c': 3 };

var newObject = myMap( myObject, function ( value, key ) {
    return value * value;
});

评论

0赞 ankhzet 2/17/2016
性能问题:绝对冗余。1) 没有回调就没有意义 2) 如果不是函数,您的实现只是运行毫无意义的 for 循环。另外,有点矫枉过正。typeof callback === 'function'mapcallbackmapObject.prototype.hasOwnProperty.call( obj, key )
61赞 Alnitak 2/11/2013 #2

写一个很容易:

Object.map = function(o, f, ctx) {
    ctx = ctx || this;
    var result = {};
    Object.keys(o).forEach(function(k) {
        result[k] = f.call(ctx, o[k], k, o); 
    });
    return result;
}

使用示例代码:

> o = { a: 1, b: 2, c: 3 };
> r = Object.map(o, function(v, k, o) {
     return v * v;
  });
> r
{ a : 1, b: 4, c: 9 }

注意:此版本还允许您(可选)设置回调的上下文,就像方法一样。thisArray

EDIT - 更改为删除 的使用,以确保它不会与对象上命名的任何现有属性冲突。Object.prototypemap

评论

7赞 JLRishe 1/28/2015
好的,:)对这个问题的评论把我带到了这里。我会 +1 这个,因为公认的答案显然是滥用的,但我必须说修改对我来说并不合适,即使它不是可枚举的。mapObject.prototype
2赞 Alnitak 1/28/2015
@JLRishe谢谢。恕我直言,在 ES5 中,除了与其他方法发生冲突的(理论上)风险之外,真的不再有任何理由修改。FWIW,我不明白另一个答案是如何获得这么多票的,这是完全错误的。Object.prototype
2赞 JLRishe 1/28/2015
是的,碰撞是我想到的,尤其是像 .map
3赞 fregante 8/8/2016
已经行不通了:.你冒着风险只是为了写作而不是o = {map: true, image: false}o.map(fn)map(o,fn)
2赞 Alnitak 8/8/2016
@bfred.it 我已经进行了相应的更新。我要指出的是,这只会消除与同名属性发生冲突的风险。我检查了一下,属性太少了,我认为如果 ES 确实获得了这种方法,那将是而不是(这也与 上的其他“静态”方法一致ObjectObject.mapObject.prototype.mapObject)
2515赞 Amberlamps 2/11/2013 #3

该对象没有原生的,但是这个怎么样:mapObject

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)) 

评论

31赞 Alnitak 7/18/2014
@KhalilRavanna我认为你误读了这里的代码 - 这个答案没有正确使用,因为它没有做一个 - 它滥用,就好像它是一个电话一样。如果他真的这样做了,那么结果将是一个包含双倍原始值的数组,而不是一个包含具有双倍值的原始键的对象,后者显然是 OP 所要求的。mapreturnmapforEachreturn myObject[value] * 2
3赞 Alnitak 3/6/2015
@Amberlamps您的示例没问题,但恕我直言,它仍然远远低于 for Objects 的便利性,因为您的回调不仅必须与工作方式相匹配,而且还要求在词法范围内可用。特别是后者,不可能只在回调中传递函数引用,而是需要就地匿名函数。.reduce.map.reduce.reducemyObject
14赞 mejdev 2/27/2016
TBH:我宁愿只(或最初)提供此答案中提出的第二个解决方案的答案投赞成票。第一个有效,不一定是错误的,但正如其他人所说,我不喜欢看到地图被这样使用。当我看到 map 时,我的大脑会自动思考“不可变的数据结构”
9赞 CertainPerformance 12/3/2018
.map当您不打算使用生成的映射数组时,这不是合适的方法 - 如果您只想产生副作用,例如在您的第一个代码中,您绝对应该改用。forEach
5赞 CertainPerformance 5/27/2020
Object.fromEntries是 ES2019,而不是 ES2015。此外,正如其他人所说,我强烈建议将第一个代码段中的替换为 ,或者其他比.mapforEach.map
27赞 Mattias Buelens 2/11/2013 #4

您可以使用 Object.keys,然后对返回的键数组进行操作:forEach

var myObject = { 'a': 1, 'b': 2, 'c': 3 },
    newObject = {};
Object.keys(myObject).forEach(function (key) {
    var value = myObject[key];
    newObject[key] = value * value;
});

或者以更模块化的方式:

function map(obj, callback) {
    var result = {};
    Object.keys(obj).forEach(function (key) {
        result[key] = callback.call(obj, obj[key], key, obj);
    });
    return result;
}

newObject = map(myObject, function(x) { return x * x; });

请注意,它返回一个仅包含对象自己的可枚举属性的数组,因此它的行为类似于带有检查的循环。Object.keysfor..inhasOwnProperty

150赞 Mario 12/19/2013 #5

没有原生方法,但 lodash#mapValues 会出色地完成这项工作

_.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
// → { 'a': 3, 'b': 6, 'c': 9 }

评论

9赞 10/3/2017
无需仅为一个函数添加额外的 HTTP 调用和额外的库。无论如何,这个答案现在已经过时了,你可以简单地调用来获取一个数组。Object.entries({a: 1, b: 2, c: 3})
21赞 corse32 12/4/2017
为什么获取数组有用?要求是映射对象。此外,在使用 Lodash 时也没有隐含的 HTTP 调用,Lodash 是一个流行的库,本质上是为这类事情构建的,尽管 ES6 最近在某种程度上排除了使用实用程序函数库的必要性。
6赞 igorsantos07 3/29/2018
我猜是额外的 HTTP 调用来拉取 Lodash。如果这是你唯一的用例,那确实是矫枉过正。尽管如此,有这个答案是有道理的,因为 Lodash 是一个如此广泛的图书馆。
2赞 igorsantos07 3/29/2018
更不用说你应该实际使用,这样你就得到了密钥作为第二个参数 - 正如 OP 所要求的那样。_.map()
5赞 MeltedPenguin 6/4/2020
_.mapValues()还提供密钥作为第二个参数。这里也不起作用,因为它只返回数组,而不是对象:_.map()_.map({ 'a': 1, 'b': 2, 'c': 3}, n => n * 3) // [3, 6, 9]
0赞 MattiSG 3/16/2015 #6

如果你不仅对 ping 值感兴趣,还对键感兴趣,我编写了 Object.map(valueMapper, keyMapper),其行为方式如下:map

var source = { a: 1, b: 2 };
function sum(x) { return x + x }

source.map(sum);            // returns { a: 2, b: 4 }
source.map(undefined, sum); // returns { aa: 1, bb: 2 }
source.map(sum, sum);       // returns { aa: 2, bb: 4 }

评论

0赞 MattiSG 10/17/2016
如果对任何人有用:.npm install @mattisg/object.map
18赞 JoeTron 10/22/2015 #7

我来到这里寻找并将对象映射到数组的答案,并因此得到了这个页面。如果你来这里寻找与我相同的答案,这里是如何映射和反对数组。

您可以使用 map 从对象返回一个新数组,如下所示:

var newObject = Object.keys(myObject).map(function(key) {
   return myObject[key];
});

评论

9赞 Alnitak 8/8/2016
这不能远程工作 - 它只是返回对象值的数组,而不是新对象。我简直不敢相信它有这么多的赞成票。
1赞 JoeTron 8/10/2016
你是对的,它没有正确回答问题,因为他们正在寻找将对象映射到对象的答案。我来到这里寻找将对象映射到数组的答案,并因此得到了这个页面,所以我将留下我的答案并对其进行编辑,以反映它是那些可能因寻找对象映射到数组而到达这里的人的替代答案。
10赞 Alnitak 8/10/2016
在 ES7 中,这将是微不足道的Object.values(myObject)
0赞 Mahdi Bashirpour 6/11/2018
const obj = { foo: 'bar', baz: 42 };console.log(Object.entries(obj));[ ['foo', 'bar'], ['baz', 42] ]
0赞 SujithaW 11/16/2021
这不起作用,只是输出一个带有对象值的数组
0赞 Zak 1/22/2016 #8

嘿,写了一个小的映射器函数,可能会有所帮助。

    function propertyMapper(object, src){
         for (var property in object) {   
           for (var sourceProp in src) {
               if(property === sourceProp){
                 if(Object.prototype.toString.call( property ) === '[object Array]'){
                   propertyMapper(object[property], src[sourceProp]);
                   }else{
                   object[property] = src[sourceProp];
                }
              }
            }
         }
      }
3赞 yonatanmn 2/2/2016 #9

根据@Amberlamps答案,这里有一个效用函数 (作为评论,它看起来很丑)

function mapObject(obj, mapFunc){
    return Object.keys(obj).reduce(function(newObj, value) {
        newObj[value] = mapFunc(obj[value]);
        return newObj;
    }, {});
}

用途是:

var obj = {a:1, b:3, c:5}
function double(x){return x * 2}

var newObj = mapObject(obj, double);
//=>  {a: 2, b: 6, c: 10}
13赞 user6445533 8/4/2016 #10

公认的答案有两个缺点:

  • 它误用了 ,因为 reduce 意味着改变复合类型的结构,而这种情况不会发生。Array.prototype.reduce
  • 它不是特别可重复使用

ES6/ES2015 功能方法

请注意,所有函数均以咖喱形式定义。

// small, reusable auxiliary functions

const keys = o => Object.keys(o);

const assign = (...o) => Object.assign({}, ...o);

const map = f => xs => xs.map(x => f(x));

const mul = y => x => x * y;

const sqr = x => mul(x) (x);


// the actual map function

const omap = f => o => {
  o = assign(o); // A
  map(x => o[x] = f(o[x])) (keys(o)); // B
  return o;
};


// mock data

const o = {"a":1, "b":2, "c":3};


// and run

console.log(omap(sqr) (o));
console.log(omap(mul(10)) (o));

  • 在行 A 中被重新分配。由于 Javascript 通过共享传递引用值,因此会生成 的浅拷贝。现在,我们可以在不改变父作用域的情况下进行变异。oooomapo
  • 在行 B 中,返回值被忽略,因为执行了 的突变。由于此副作用保留在父范围中,并且在父范围中不可见,因此完全可以接受。mapmapoomap

这不是最快的解决方案,而是一个声明性和可重用的解决方案。这是与单行相同的实现,简洁但可读性较差:

const omap = f => o => (o = assign(o), map(x => o[x] = f(o[x])) (keys(o)), o);

附录 - 为什么默认情况下对象不可迭代?

ES2015 指定了迭代器和可迭代协议。但是对象仍然不可迭代,因此不可映射。原因是数据和程序级别的混合

评论

1赞 fregante 8/8/2016
看起来有点过度设计;我计算了 6 个函数,本质上是一个循环。其他解决方案要简单得多,公认的答案也快 5 倍。
5赞 8/8/2016
@bfred.it 你评论的目的是什么?如果你喜欢微优化,你也不应该使用。我在这里想说明的是,公认的答案在某种程度上“滥用”了,以及如何实现纯粹的功能映射。如果你对函数式编程不感兴趣,请忽略我的回答。Array.prototype.reduceArray.prototype.reduce
0赞 fregante 8/8/2016
如果您对性能和简单性不感兴趣,请不要阅读我的评论。:)许多功能被“滥用”,但有时它们比其他解决方案更适合滥用。
2赞 Dtipson 7/13/2017
“减少意味着改变复合类型的结构”我不认为这是真的。生成长度完全相同甚至值完全相同的新数组的 Array.reduce 是完全合法的。Reduce可用于重新创建map和/或filter的功能(或两者兼而有之,如在复杂的换能器中,reduce是其基础)。在 FP 中,它是一种折叠,最终以相同类型结束的折叠仍然是折叠。
2赞 7/13/2017
@Dtipson 你是绝对正确的。A 比 a(函子)更通用。然而,这是我从 2016 年年中开始的知识。那是半个永恒:Dfoldmap
586赞 Rotareti 8/8/2016 #11

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 中,您不能使用 ,但您可以将 Object.assign扩展运算符计算键名称语法结合使用来实现相同的目的:Objects.fromEntries

let newObj = Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v})));

ES6 [美]/ES2015 [美]不允许,但您可以改用 Object.keysObject.entries

let newObj = Object.assign({}, ...Object.keys(obj).map(k => ({[k]: obj[k] * obj[k]})));

ES6 还引入了...的循环,它允许更命令式的样式:

let newObj = {}

for (let [k, v] of Object.entries(obj)) {
  newObj[k] = v * v;
}


array.reduce()

而不是 ,你也可以为此使用 reduceObject.fromEntriesObject.assign

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'
}

但是,请帮我一个忙,避免继承。:-)

评论

1赞 David Braun 3/14/2017
很漂亮,但我被没有枚举继承属性的事实所吸引。我建议你添加一个警告。Object.keys
0赞 10/3/2017
要缩短您的答案,只需使用 .Object.entries({a: 1, b: 2, c: 3})
1赞 kzahel 10/12/2017
你有一些错别字(你指的是参数,但在正文中使用。(o, f)obj
0赞 Jakub Małojło 12/4/2017
嘿,你能提供更多关于为什么我们应该避免继承的信息吗?一些好文章就足够了:)
1赞 blackcatweb 7/11/2019
如果为空对象,则该解决方案不起作用。更改为:。Object.assign(...Object.entries(obj).map(([k, v]) => ({[k]: v * v})))objObject.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v})))
6赞 Mulan 8/9/2016 #12

编辑:使用较新的 JavaScript 功能的规范方式是 -

const identity = x =>
  x

const omap = (f = identity, o = {}) =>
  Object.fromEntries(
    Object.entries(o).map(([ k, v ]) =>
      [ k, f(v) ]
    )
  )

其中是某个对象,是您的映射函数。或者我们可以说,给定一个来自 的函数和一个具有 类型值的对象,生成一个具有 类型值的对象。作为伪类型签名 -ofa -> bab

// omap : (a -> b, { a }) -> { b }

最初的答案是为了演示一个强大的组合器而写的,它使我们能够以不同的方式思考我们的转换mapReduce

  1. m映射函数 – 让您有机会在...
  2. r约简函数 – 此函数将累加器与映射元素的结果相结合

直观地,创建一个我们可以直接插入的新减速器。但更重要的是,我们可以通过使用对象 monoid 和 .mapReduceArray.prototype.reduceomapObject.assign{}

const identity = x =>
  x
  
const mapReduce = (m, r) =>
  (a, x) => r (a, m (x))

const omap = (f = identity, o = {}) =>
  Object
    .keys (o)
    .reduce
      ( mapReduce
          ( k => ({ [k]: f (o[k]) })
          , Object.assign
          )
      , {}
      )
          
const square = x =>
  x * x
  
const data =
  { a : 1, b : 2, c : 3 }
  
console .log (omap (square, data))
// { a : 1, b : 4, c : 9 }

请注意,我们实际上必须编写的程序的唯一部分是映射实现本身——

k => ({ [k]: f (o[k]) })

也就是说,给定一个已知对象和某个键,构造一个对象,其计算属性是调用键的值的结果。okkfo[k]

如果我们首先抽象,我们就会瞥见 的测序潜力mapReduceoreduce

// oreduce : (string * a -> string * b, b, { a }) -> { b }
const oreduce = (f = identity, r = null, o = {}) =>
  Object
    .keys (o)
    .reduce
      ( mapReduce
          ( k => [ k, o[k] ]
          , f
          )
      , r
      )

// omap : (a -> b, {a}) -> {b}
const omap = (f = identity, o = {}) =>
  oreduce
    ( mapReduce
        ( ([ k, v ]) =>
            ({ [k]: f (v) })
        , Object.assign
        )
    , {}
    , o
    )

一切都是一样的,但现在可以在更高的层次上定义。当然,新的方法使这看起来很傻,但练习对学习者来说仍然很重要。omapObject.entries

你不会在这里看到它的全部潜力,但我分享这个答案,因为看看它可以应用多少地方很有趣。如果您对它是如何派生的以及它可能有用的其他方式感兴趣,请参阅此答案mapReduce

评论

4赞 8/9/2016
让我们宁愿使用 和 ,OK :D。我厌倦了滥用普通对象作为地图数据类型。MapMap.entries
2赞 Mulan 8/9/2016
我同意应该在可能的地方/时间使用,但它并不能完全取代在普通 JS 对象上使用这些过程的需要:DMap
1赞 Symmetric 8/11/2016 #13

我需要一个允许修改密钥的版本(基于 @Amberlamps 和 @yonatanmn 答案);

var facts = [ // can be an object or array - see jsfiddle below
    {uuid:"asdfasdf",color:"red"},
    {uuid:"sdfgsdfg",color:"green"},
    {uuid:"dfghdfgh",color:"blue"}
];

var factObject = mapObject({}, facts, function(key, item) {
    return [item.uuid, {test:item.color, oldKey:key}];
});

function mapObject(empty, obj, mapFunc){
    return Object.keys(obj).reduce(function(newObj, key) {
        var kvPair = mapFunc(key, obj[key]);
        newObj[kvPair[0]] = kvPair[1];
        return newObj;
    }, empty);
}

factObject=

{
"asdfasdf": {"color":"red","oldKey":"0"},
"sdfgsdfg": {"color":"green","oldKey":"1"},
"dfghdfgh": {"color":"blue","oldKey":"2"}
}

编辑:稍作改动以传入起始对象 {}。允许它为 [](如果键是整数)

-1赞 Jason Norwood-Young 10/3/2016 #14

我特别想使用与单个对象数组相同的函数,并希望保持简单。这对我有用:

var mapped = [item].map(myMapFunction).pop();

评论

2赞 Mulan 7/18/2019
这与var mapped = myMapFunction(item)
10赞 Pawel 10/3/2016 #15

实现最佳性能。

如果你的对象不经常改变,但需要经常迭代,我建议使用原生Map作为缓存。

// example object
var obj = {a: 1, b: 2, c: 'something'};

// caching map
var objMap = new Map(Object.entries(obj));

// fast iteration on Map object
objMap.forEach((item, key) => {
  // do something with an item
  console.log(key, item);
});

Object.entries 已经在 Chrome、Edge、Firefox 和 beta Opera 中运行,因此它是一项面向未来的功能。 它来自 ES7,因此 polyfill https://github.com/es-shims/Object.entries 它不适用于 IE。

评论

0赞 Константин Ван 12/13/2016
使用Destructing怎么样?
1赞 Pawel 12/13/2016
@K._ 以前很慢,但现在不知道性能了。看起来 V8 v 5.6 引入了一些解构优化,但这必须 v8project.blogspot.co.uk
0赞 mikebridge 1/26/2017
或者,性能较低的 es7 但不可变:const fn = v => v * 2; const newObj = Object.entries(myObject).reduce((acc, [k,v]) => Object.assign({}, acc, {[k]: fn(v)}), {});
27赞 Alexander Mills 10/13/2016 #16

这真的很烦人,JS社区的每个人都知道。应该有这个功能:

const obj1 = {a:4, b:7};
const obj2 = Object.map(obj1, (k,v) => v + 5);
    
console.log(obj1); // {a:4, b:7}
console.log(obj2); // {a:9, b:12}

这是朴素的实现:

Object.defineProperty(Object, 'map', {
    value: function(obj, fn, ctx) {
        const ret = {};

        for(let k of Object.keys(obj)){
            ret[k] = fn.call(ctx || null, k, obj[k]);
        });

        return ret;
    },
    enumerable: false
};

必须一直自己实现这一点是超级烦人的;)

如果你想要一些更复杂的东西,不会干扰 Object 类,请尝试以下操作:

const map = function (obj, fn, ctx) {
  return Object.keys(obj).reduce((a, b) => {
    a[b] = fn.call(ctx || null, b, obj[b]);
    return a;
  }, {});
};


const x = map({a: 2, b: 4}, (k,v) => {
    return v*2;
});

将此映射函数添加到 ;注意不要直接分配给 - 如果要扩展原型,请使用ObjectObject.prototypeObject.definePropertyenumerable: false

// fairly safe:
Object.map = ...

// not ok (causes all objects to have a "map" property):
Object.prototype.map ...

// fairly safe:
Object.defineProperty(Object.prototype, map, { value: ..., enumerable: false });

评论

1赞 Amberlamps 10/14/2016
为什么要将此函数添加到全局对象中?只要有.Objectconst mapObject = (obj, fn) => { [...]; return ret; }
8赞 Alexander Mills 10/14/2016
因为它应该是对象 :) 上的方法
1赞 Alexander Mills 10/14/2016
只要我们不弄乱 Object.prototype,那么我们应该没问题
1赞 Dtipson 7/13/2017
如果地图只是一个随机的模糊的东西,当然。但通常被理解为 Functor 接口,并且 Functor 没有针对“对象”的单一定义,因为 javascript 中几乎任何内容都可以是 Object,包括具有自己非常独特和定义的 .map 接口/逻辑的事物。.map
1赞 Gleb Dolzikov 2/1/2018
在我看来,回调的第一个参数应该是迭代元素本身,而不是键。例如,我假设它应该给我相同的对象,就像它通常发生在公共映射中一样:Object.map({prop:1}, el => el),但它返回具有相同键名值的键......
1赞 Dmitry Ragozin 11/16/2016 #17
var myObject = { 'a': 1, 'b': 2, 'c': 3 };


Object.prototype.map = function(fn){
    var oReturn = {};
    for (sCurObjectPropertyName in this) {
        oReturn[sCurObjectPropertyName] = fn(this[sCurObjectPropertyName], sCurObjectPropertyName);
    }
    return oReturn;
}
Object.defineProperty(Object.prototype,'map',{enumerable:false});





newObject = myObject.map(function (value, label) {
    return value * value;
});


// newObject is now { 'a': 1, 'b': 4, 'c': 9 }

评论

0赞 Mulan 7/18/2019
enumerable默认为false
23赞 Yukulélé 7/18/2017 #18

最低版本

ES2017 (英语)

Object.entries(obj).reduce((a, [k, v]) => (a[k] = v * v, a), {})
                                                  ↑↑↑↑↑

ES2019 (英语)

Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, v * v]))
                                                           ↑↑↑↑↑

评论

0赞 Alexander Mills 1/31/2018
我认为这是不正确的,因为拼写错误,我认为您的意思是 => ,尖括号而不是括号。Object.entries(obj).reduce((a, [k, v]) => [a[k] = v * v, a], {})
0赞 Yukulélé 1/31/2018
@AlexanderMills,我的代码是正确的。阅读更多关于括号内的逗号运算符:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
1赞 Yukulélé 1/31/2018
基本上,我的代码等同于:Object.entries(obj).reduce((a, [k, v]) => {a[k] = v * v; return a}, {})
0赞 Alexander Mills 1/31/2018
Webstorm 警告开发人员使用“逗号表达式”,称它们“通常是过于聪明的代码的标志”......哈哈只是说'
0赞 Yukulélé 1/31/2018
他是对的。要获得更易于理解的代码,请使用 loop: stackoverflow.com/a/14810722/806169
3赞 alex.h 1/8/2018 #19

我在 Google 搜索中发现这是第一项,试图学习这样做,并认为我会为其他 folsk 分享我最近找到的解决方案,它使用 npm 包不可变。

我认为分享它很有趣,因为 immutable 在他们自己的文档中使用了 OP 的确切情况 - 以下不是我自己的代码,而是从当前的 immutable-js 文档中提取的:

const { Seq } = require('immutable')
const myObject = { a: 1, b: 2, c: 3 }
Seq(myObject).map(x => x * x).toObject();
// { a: 1, b: 4, c: 9 } 

并不是说 Seq 有其他属性(“Seq 描述了一个惰性操作,允许他们通过不创建中间集合来有效地链接所有高阶集合方法(例如 map 和 filter)的使用”),并且其他一些不可变的 js 数据结构也可能非常有效地完成这项工作。

当然,任何使用此方法的人都必须并且可能想要阅读文档:npm install immutable

https://facebook.github.io/immutable-js/

-2赞 Parth Raval 4/9/2018 #20

const orig = { 'a': 1, 'b': 2, 'c': 3 }

const result = _.transform(orig, (r, v, k) => r[k.trim()] = v * 2);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

使用 new _.transform() 转换对象

1赞 tailattention 5/23/2018 #21

如果有人正在寻找将对象映射到新对象或数组的简单解决方案:

// Maps an object to a new object by applying a function to each key+value pair.
// Takes the object to map and a function from (key, value) to mapped value.
const mapObject = (obj, fn) => {
    const newObj = {};
    Object.keys(obj).forEach(k => { newObj[k] = fn(k, obj[k]); });
    return newObj;
};

// Maps an object to a new array by applying a function to each key+value pair.
// Takes the object to map and a function from (key, value) to mapped value.
const mapObjectToArray = (obj, fn) => (
    Object.keys(obj).map(k => fn(k, obj[k]))
);

这可能不适用于所有对象或所有映射函数,但它适用于普通的浅层对象和简单的映射函数,这就是我所需要的。

0赞 Endless 7/31/2018 #22

另一种看法是使用自定义 json stringify 函数,该函数也可以处理深层对象。如果您打算将其作为 json 发布到服务器,这可能很有用

const obj = { 'a': 1, 'b': 2, x: {'c': 3 }}
const json = JSON.stringify(obj, (k, v) => typeof v === 'number' ? v * v : v)

console.log(json)
console.log('back to json:', JSON.parse(json))

8赞 Haritsinh Gohil 9/29/2018 #23

你可以使用 method 和 on 数组,但如果你想使用它,那么你可以像下面这样使用它:mapforEachObject

使用 Javascript (ES6)

var obj = { 'a': 2, 'b': 4, 'c': 6 };   
Object.entries(obj).map( v => obj[v[0]] *= v[1] );
console.log(obj); //it will log as {a: 4, b: 16, c: 36}

var obj2 = { 'a': 4, 'b': 8, 'c': 10 };
Object.entries(obj2).forEach( v => obj2[v[0]] *= v[1] );
console.log(obj2); //it will log as {a: 16, b: 64, c: 100}

使用 jQuery

var ob = { 'a': 2, 'b': 4, 'c': 6 };
$.map(ob, function (val, key) {
   ob[key] *= val;
});
console.log(ob) //it will log as {a: 4, b: 16, c: 36}

或者您也可以使用其他循环,例如方法,如下例所示:$.each

$.each(ob,function (key, value) {
  ob[key] *= value;
});
console.log(ob) //it will also log as {a: 4, b: 16, c: 36}

评论

0赞 masterxilo 10/13/2018
jquery在哪里?$
0赞 Haritsinh Gohil 10/13/2018
是的,您可以同时使用 $ 和 jQuery
1赞 Haritsinh Gohil 10/30/2018
@Ronald我误解了,请参阅我更新的答案,感谢您没有投反对票,而是真正意识到我的错误,感谢您改善社区。
0赞 Haritsinh Gohil 12/6/2018
@bcoughlan是的,这也正是我在评论中写的,它正在平方数字,那你想要什么?
1赞 abalter 9/17/2019
@HaritsinhGohil我认为他的意思是他批评你给出了一个jQuery解决方案。诚然,现在有一些动力要远离 jQuery,当然还有 Node,但除非 OP 特别要求纯 JS 或 Node,否则我认为假设有人在 Web 环境中工作并且 jQuery 几乎肯定是可用的。
1赞 humanityANDpeace 12/9/2018 #24

为了更接近 OP 所要求的内容,OP 需要一个对象:

myObject = { 'a': 1, 'b': 2, 'c': 3 }

要有一个 map 方法,myObject.map

类似于 Array.prototype.map,其使用方式如下:

newObject = myObject.map(function (value, label) {
    return value * value;
});
// newObject is now { 'a': 1, 'b': 4, 'c': 9 }

恕我直言,最好的答案(以“接近所要求的”+“不需要不必要的 ES{5,6,7}”来衡量)答案是:

myObject.map = function mapForObject(callback)
{
  var result = {};
  for(var property in this){
    if(this.hasOwnProperty(property) && property != "map"){
      result[property] = callback(this[property],property,this);
    }
  }
  return result;
}

上面的代码避免了有意使用任何语言功能,这些功能仅在最近的 ECMAScript 版本中可用。使用上面的代码可以解决这个问题:

myObject = { 'a': 1, 'b': 2, 'c': 3 };

myObject.map = function mapForObject(callback)
{
  var result = {};
  for(var property in this){
    if(this.hasOwnProperty(property) && property != "map"){
      result[property] = callback(this[property],property,this);
    }
  }
  return result;
}

newObject = myObject.map(function (value, label) {
  return value * value;
});
console.log("newObject is now",newObject);
替代测试代码在这里

除了一些人不赞成之外,还可以像这样将解决方案插入原型链中。

Object.prototype.map = function(callback)
{
  var result = {};
  for(var property in this){
    if(this.hasOwnProperty(property)){
      result[property] = callback(this[property],property,this);
    }
  }
  return result;
}

某些东西,当在仔细的监督下完成时,不应该产生任何不良影响,也不会影响其他对象(即 Array)的方法。mapmap

1赞 Jimubao 1/10/2019 #25

首先,使用 Object.entries(collection) 转换 HTMLCollection。然后它是一个可迭代的,你现在可以在它上面使用 .map 方法。

Object.entries(collection).map(...)

参考 https://medium.com/@js_tut/calling-javascript-code-on-multiple-div-elements-without-the-id-attribute-97ff6a50f31

2赞 user10555044 2/7/2019 #26

我的回答很大程度上是基于这里评分最高的回答,希望每个人都能理解(在我的GitHub上也有同样的解释)。这就是为什么他用地图进行激励工作的原因:

Object.keys(images).map((key) => images[key] = 'url(' + '"' + images[key] + '"' +    
')');

该函数的目的是获取一个对象,并使用可用于所有对象(对象和数组)的方法修改对象的原始内容,而不返回数组。JS 中的几乎所有东西都是一个对象,因此,继承管道下游的元素在技术上可能会使用那些可供上层元素使用的元素(反之亦然)。

这样做的原因是 .map 函数返回数组,要求您提供数组的显式或隐式 RETURN,而不是简单地修改现有对象。你基本上通过使用 Object.keys 欺骗程序认为对象是一个数组,这将允许你使用 map 函数,它作用于与各个键关联的值(我实际上不小心返回了数组,但修复了它)。只要没有正常意义上的返回,就不会有原始对象完好无损并按编程修改的数组。

这个特定的程序接受一个名为 images 的对象,并获取其键的值,并附加 url 标签以在另一个函数中使用。原文是这样的:

var images = { 
snow: 'https://www.trbimg.com/img-5aa059f5/turbine/bs-md-weather-20180305', 
sunny: 'http://www.cubaweather.org/images/weather-photos/large/Sunny-morning-east-   
Matanzas-city- Cuba-20170131-1080.jpg', 
rain: 'https://i.pinimg.com/originals/23/d8
/ab/23d8ab1eebc72a123cebc80ce32b43d8.jpg' };

...修改后是这样的:

var images = { 
snow: url('https://www.trbimg.com/img-5aa059f5/turbine/bs-md-weather-20180305'),     
sunny: url('http://www.cubaweather.org/images/weather-photos/large/Sunny-morning-   
east-Matanzas-city- Cuba-20170131-1080.jpg'), 
rain: url('https://i.pinimg.com/originals/23/d8
/ab/23d8ab1eebc72a123cebc80ce32b43d8.jpg') 
};

对象的原始结构保持不变,只要没有返回,就可以进行正常的属性访问。不要让它像往常一样返回数组,一切都会好起来的。目标是将原始值 (images[key]) 重新分配给所需的值,而不是其他任何值。据我所知,为了防止数组输出,必须重新分配图像[key],并且没有隐式或显式请求返回数组(变量赋值可以做到这一点,并且对我来说来回出现故障)。

编辑:

将解决他关于创建新对象的另一种方法,以避免修改原始对象(并且为了避免意外创建数组作为输出,重新分配似乎仍然是必要的)。这些函数使用箭头语法,如果您只想创建一个新对象以供将来使用,则使用箭头语法。

const mapper = (obj, mapFn) => Object.keys(obj).reduce((result, key) => {
                result[key] = mapFn(obj)[key];
                return result;
            }, {});

var newImages = mapper(images, (value) => value);

这些函数的工作方式是这样的:

mapFn 接受稍后要添加的函数(在本例中为 (value) => value),并简单地返回存储在该键的任何内容作为该键的值(或者如果您像他一样更改返回值,则乘以 2)在 mapFn(obj)[key],

然后重新定义与 result[key] = mapFn(obj)[key] 中的键关联的原始值

并返回对 result(位于 .reduce 函数末尾启动的括号中的累加器)执行的操作。

所有这些都是在所选对象上执行的,并且仍然不能对返回的数组进行隐式请求,并且仅在重新分配值时才有效。这需要一些心理体操,但减少了所需的代码行,如上所示。输出完全相同,如下所示:

{snow: "https://www.trbimg.com/img-5aa059f5/turbine/bs-   
md-weather-20180305", sunny: "http://www.cubaweather.org/images/weather-
photos/l…morning-east-Matanzas-city-Cuba-20170131-1080.jpg", rain: 
"https://i.pinimg.com/originals/23/d8
/ab/23d8ab1eebc72a123cebc80ce32b43d8.jpg"}

请记住,这适用于 NON-NUMBERS。您可以通过简单地在 mapFN 函数中返回值来复制任何对象。

-2赞 Akın Köker 3/2/2019 #27
settings = {
  message_notification: {
    value: true,
    is_active: true,
    slug: 'message_notification',
    title: 'Message Notification'
  },
  support_notification: {
    value: true,
    is_active: true,
    slug: 'support_notification',
    title: 'Support Notification'
  },
};

let keys = Object.keys(settings);
keys.map(key=> settings[key].value = false )
console.log(settings)
17赞 HaNdTriX 5/13/2019 #28

JavaScript 刚刚有了新方法。Object.fromEntries

function mapObject (obj, fn) {
  return Object.fromEntries(
    Object
      .entries(obj)
      .map(fn)
  )
}

const myObject = { a: 1, b: 2, c: 3 }
const myNewObject = mapObject(myObject, ([key, value]) => ([key, value * value]))
console.log(myNewObject)

解释

上面的代码将 Object 转换为嵌套的数组 (),您可以映射它。 将 Array 转换回 Object。[[<key>,<value>], ...]Object.fromEntries

这种模式很酷的地方在于,您现在可以在映射时轻松地将对象键考虑在内。

文档

浏览器支持

Object.fromEntries目前仅受这些浏览器/引擎支持,但仍有可用的 polyfills(例如 @babel/polyfill)。

评论

2赞 orad 7/18/2019
基本上,是 的反义词。 将对象转换为键值对列表。 将键值对列表转换为对象。Object.fromEntriesObject.entriesObject.entriesObject.fromEntries
0赞 Simon East 10/31/2021
不错的解决方案。干净简单。除了函数参数不同于 。我的偏好是地图函数参数是 .我知道这似乎有点倒退,但这是使用的顺序,所以它更一致。Array.map()(value, key)Array.map()Array.forEach()
-2赞 Malix Ren 5/31/2019 #29

ES6 (美):

Object.prototype.map = function(mapFunc) {
    return Object.keys(this).map((key, index) => mapFunc(key, this[key], index));
}

ES2015 格式:

Object.prototype.map = function (mapFunc) {
    var _this = this;

    return Object.keys(this).map(function (key, index) {
        return mapFunc(key, _this[key], index);
    });
};

在节点中测试:

> a = {foo: "bar"}
{ foo: 'bar' }
> a.map((k,v,i) => v)
[ 'bar' ]
1赞 Idan 8/6/2019 #30

我只处理字符串以减少豁免:

Object.keys(params).map(k => typeof params[k] == "string" ? params[k] = params[k].trim() : null);
4赞 orad 8/14/2019 #31

TypeScript 中的对象映射器

我喜欢使用这样的示例,但是它们仍然不是很容易使用。使用然后查找的答案实际上是在进行多次查找,这些查找可能不是必需的。Object.fromEntriesObject.keyskey

我希望有一个函数,但我们可以创建自己的函数并调用它,并能够修改两者和:Object.mapobjectMapkeyvalue

用法 (JavaScript):

const myObject = { 'a': 1, 'b': 2, 'c': 3 };

// keep the key and modify the value
let obj = objectMap(myObject, val => val * 2);
// obj = { a: 2, b: 4, c: 6 }


// modify both key and value
obj = objectMap(myObject,
    val => val * 2 + '',
    key => (key + key).toUpperCase());
// obj = { AA: '2', BB: '4', CC: '6' }

代码(TypeScript):

interface Dictionary<T> {
    [key: string]: T;
}

function objectMap<TValue, TResult>(
    obj: Dictionary<TValue>,
    valSelector: (val: TValue, obj: Dictionary<TValue>) => TResult,
    keySelector?: (key: string, obj: Dictionary<TValue>) => string,
    ctx?: Dictionary<TValue>
) {
    const ret = {} as Dictionary<TResult>;
    for (const key of Object.keys(obj)) {
        const retKey = keySelector
            ? keySelector.call(ctx || null, key, obj)
            : key;
        const retVal = valSelector.call(ctx || null, obj[key], obj);
        ret[retKey] = retVal;
    }
    return ret;
}

如果您没有使用 TypeScript,请在 TypeScript Playground 中复制上述代码以获取 JavaScript 代码。

另外,我放在参数列表中的原因是因为它是可选的。keySelectorvalSelector

* 部分功劳归功于亚历山大-米尔斯的回答

评论

0赞 Kevin Borders 10/18/2023
这不适用于 obj 上的可选属性。为此,您可以在创建字典时将它们单独挑选出来并将它们合并在一起。类似这样: type Dictionary<T extends object, TValue> = { [key in RequiredKeys<T>]: TValue; } & { [key in OptionalKeys<T>]?: TValue;
2赞 Stan 10/19/2019 #32
const mapObject = (targetObject, callbackFn) => {
    if (!targetObject) return targetObject;
    if (Array.isArray(targetObject)){
        return targetObject.map((v)=>mapObject(v, callbackFn))
    }
    return Object.entries(targetObject).reduce((acc,[key, value]) => {
        const res = callbackFn(key, value);
        if (!Array.isArray(res) && typeof res ==='object'){
            return {...acc, [key]: mapObject(res, callbackFn)}
        }
        if (Array.isArray(res)){
            return {...acc, [key]: res.map((v)=>mapObject(v, callbackFn))}
        }
        return {...acc, [key]: res};
    },{})
};
const mapped = mapObject(a,(key,value)=> {
    if (!Array.isArray(value) && key === 'a') return ;
    if (!Array.isArray(value) && key === 'e') return [];
    if (!Array.isArray(value) && key === 'g') return value * value;
    return value;
});
console.log(JSON.stringify(mapped)); 
// {"b":2,"c":[{"d":2,"e":[],"f":[{"g":4}]}]}

此函数以递归方式遍历对象和对象数组。如果返回 undefined,则可以删除属性

9赞 Danubio Müller 4/5/2020 #33

只需使用以下命令即可将对象转换为数组:

您可以将对象值转换为数组:

myObject = { 'a': 1, 'b': 2, 'c': 3 };

let valuesArray = Object.values(myObject);

console.log(valuesArray);

您可以将对象键转换为数组:

myObject = { 'a': 1, 'b': 2, 'c': 3 };

let keysArray = Object.keys(myObject);

console.log(keysArray);

现在您可以执行正常的数组操作,包括“map”函数

评论

0赞 Doud 8/7/2020
在2020年,我认为这应该是公认的答案。
-1赞 Gowtham Kumar B V 4/28/2020 #34

var myObject = { 'a': 1, 'b': 2, 'c': 3 };
Object.keys(myObject).filter((item) => myObject[item] *= 2)
console.log(myObject)

-1赞 wahyu setiawan 7/1/2020 #35

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 }

评论

1赞 mw509 7/1/2020
您可能希望始终解释您的解决方案。它使它更有用
-3赞 Kamil Kiełczewski 7/18/2020 #36

使用以下映射函数定义myObject.map

o => f=> Object.keys(o).reduce((a,c)=> c=='map' ? a : (a[c]=f(o[c],c),a), {})

let map = o => f=> Object.keys(o).reduce((a,c)=> c=='map' ? a : (a[c]=f(o[c],c),a), {})



// TEST init

myObject = { 'a': 1, 'b': 2, 'c': 3 }
myObject.map = map(myObject);        

// you can do this instead above line but it is not recommended 
// ( you will see `map` key any/all objects)
// Object.prototype.map = map(myObject);

// OP desired interface described in question
newObject = myObject.map(function (value, label) {
    return  value * value;
});

console.log(newObject);

0赞 Emilio Grisolía 5/17/2021 #37

我需要一个函数来选择性地映射不仅(也不完全)值,还有键。原始对象不应更改。该对象也只包含基元值。

function mappedObject(obj, keyMapper, valueMapper) {

    const mapped = {};
    const keys   = Object.keys(obj);
    const mapKey = typeof keyMapper == 'function';
    const mapVal = typeof valueMapper == 'function';

    for (let i = 0; i < keys.length; i++) {
        const key = mapKey ? keyMapper(keys[i]) : keys[i];
        const val = mapVal ? valueMapper(obj[keys[i]]) : obj[keys[i]];
        mapped[key] = val;
    }

    return mapped;
}

用。传递 keymapper 和 valuemapper 函数:

const o1 = { x: 1, c: 2 }
mappedObject(o1, k => k + '0', v => v + 1) // {x0: 2, c0: 3}
-1赞 loop 5/21/2021 #38

这是另一个版本,它允许映射函数根据当前键和值声明任意数量的新属性(键和值)。E:现在也适用于数组。

Object.defineProperty(Object.prototype, 'mapEntries', {
  value: function(f,a=Array.isArray(this)?[]:{}) {
    return Object.entries(this).reduce( (o, [k,v]) => 
      Object.assign(o, f(v, Array.isArray(a)?Number(k):k, this)),
      a);
  }
});

const data = { a : 1, b : 2, c : 3 };
const calculate = (v, k) => ({
  [k+'_square']: v*v,
  [k+'_cube']: v*v*v
});
console.log( data.mapEntries( calculate ) );
// {
//  "a_square": 1,  "a_cube": 1,
//  "b_square": 4,  "b_cube": 8,
//  "c_square": 9,  "c_cube": 27
// }

// Demonstration with an array:
const arr = [ 'a', 'b', 'c' ];
const duplicate = (v, i) => ({
  [i*2]: v,
  [i*2+1]: v+v
});
console.log( arr.mapEntries( duplicate ) );
// [ "a", "aa", "b", "bb", "c", "cc" ]

-2赞 panepeter 7/9/2021 #39

异步,有人吗?

尽管有大量评论,但我没有找到使用映射器的解决方案。这是我的。async

使用 p-map,一个受信任的 (@sindresorhus) 和小依赖项。

(请注意,没有选项传递给 。如果需要调整并发/错误处理,请参阅文档)。p-map

打字稿:

import pMap from "p-map";

export const objectMapAsync = async <InputType, ResultType>(
  object: { [s: string]: InputType } | ArrayLike<InputType>,
  mapper: (input: InputType, key: string, index: number) => Promise<ResultType>
): Promise<{
  [k: string]: ResultType;
}> => {
  const mappedTuples = await pMap(
    Object.entries(object),
    async ([key, value], index) => {
      const result = await mapper(value, key, index);
      return [key, result];
    }
  );

  return Object.fromEntries(mappedTuples);
};

普通 JS:

import pMap from "p-map";

export const objectMapAsync = async (
  object,
  mapper
) => {
  const mappedTuples = await pMap(
    Object.entries(object),
    async ([key, value], index) => {
      const result = await mapper(value, key, index);
      return [key, result];
    }
  );

  return Object.fromEntries(mappedTuples);
};

};

使用示例:

(高度做作,无错误处理,无类型)

// Our object in question.
const ourFavouriteCharacters = {
  me: "luke",
  you: "vader",
  everyone: "chewbacca",
};

// An async function operating on the object's values (in this case, strings)
const fetchCharacter = (charName) =>
  fetch(`https://swapi.dev/api/people?search=${charName}`)
    .then((res) => res.json())
    .then((res) => res.results[0]);

// `objectMapAsync` will return the final mapped object to us
//  (wrapped in a Promise)
objectMapAsync(ourFavouriteCharacters, fetchCharacter).then((res) =>
  console.log(res)
);

评论

3赞 ELLIOTTCABLE 9/4/2021
我不能代表你的反对者;但我认为,也许“异步映射在对象上”是一个足够独特的问题空间,它应该有自己的问题/答案,而不是一个额外的答案,它对原始提问者没有帮助,已经回答得很好,已经回答过了。(所以,少说“这很糟糕,你的也很糟糕”,而多说“这就是我们现在在 Stack Exchange 上做事的方式”。 💚
1赞 panepeter 9/4/2021
@ELLIOTTCABLE感谢您抽出宝贵时间回答我的评论。我通常只回答我自己有的问题,但我对给出的答案不满意。情况就是这样。毕竟,答案应该帮助人们找到问题,而不仅仅是海报。我冒昧地暂时保持答案不变。✌
1赞 Mecanik 10/23/2021
展示一个示例,如何为新手使用 objectMapAsync?
0赞 panepeter 10/27/2021
@Mecanik添加了一个示例,希望它有所帮助
5赞 KISHORE K J 3/7/2023 #40
  const array = Object.keys(object)
  //returns all keys as array ["key", "key"]

  const array = Object.values(object)
  //returns all values as array ["value", "value"]

  const array = Object.entries(object)
  //returns all entries as array = [["key","value"], ["key","value"]]

对结果使用 Map。

  array.map()
2赞 DLS93 7/18/2023 #41

这是我这样做的方式,结果在效率和可读性方面是值得的。

myObject = { 'a': 1, 'b': 2, 'c': 3 }

const newObject = Object.entries(myObject)
  .map(([key, value]) => `${key}: ${value * value}`)
  .join(', ');

console.log(newObject)

评论

0赞 Community 7/21/2023
您的答案可以通过额外的支持信息得到改进。请编辑以添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案是正确的。您可以在帮助中心找到有关如何写出好答案的更多信息。