1507

我有一个对象:

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 }

JavaScriptmap对对象有这样的功能吗?(我想要这个用于 Node.JS,所以我不关心跨浏览器问题。)

4

39 回答 39

2168

map该对象没有本机Object,但是如何:

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

Object.keys(myObject).map(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)) 

于 2013-02-11T10:52:37.437 回答
462

JS ES10 / ES2019中的单行代码怎么样?

使用Object.entries()and 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;
}


数组.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'
}

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

于 2016-08-08T12:20:05.757 回答
141

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

_.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
// → { 'a': 3, 'b': 6, 'c': 9 }
于 2013-12-18T16:46:13.810 回答
60

写一个很容易:

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 }

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

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

于 2013-02-11T10:52:20.620 回答
26

您可以使用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.keys返回一个仅包含对象自己的可枚举属性的数组,因此它的行为类似于for..in带有hasOwnProperty检查的循环。

于 2013-02-11T10:53:37.717 回答
25

这真的很烦人,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.map = function(obj, fn, ctx){

    const ret = {};

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

    return ret;
};

必须一直自己实现这一点非常烦人;)

如果你想要一些更复杂的东西,它不会干扰 Object 类,试试这个:

let 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;
});

但是将此映射函数添加到Object是安全的,只是不要添加到Object.prototype。

Object.map = ... // fairly safe
Object.prototype.map ... // not ok
于 2016-10-12T21:01:19.260 回答
17

我来这里是为了寻找并回答将对象映射到数组的问题,结果得到了这个页面。如果您来这里寻找与我相同的答案,这里是您如何映射和对象到数组。

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

var newObject = Object.keys(myObject).map(function(key) {
   return myObject[key];
});
于 2015-10-21T17:39:17.123 回答
17

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)

解释

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

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

文档

浏览器支持

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

于 2019-05-13T10:45:32.547 回答
14

接受的答案有两个缺点:

  • 它误用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 行o被重新分配。由于 Javascript 通过共享o传递引用值,因此生成了一个浅拷贝。我们现在可以在不改变父作用域的情况下在o内部omap进行变异o
  • 在 B 行map的返回值被忽略,因为map执行了o. 由于此副作用保留在父范围内omap且在父范围内不可见,因此完全可以接受。

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

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

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

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

于 2016-08-03T20:45:34.403 回答
13

最小版本

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]))
                                                           ↑↑↑↑↑
于 2017-07-17T22:58:21.220 回答
10

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

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

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' 函数

于 2020-04-05T08:53:12.440 回答
8

以获得最佳性能。

如果您的对象不经常更改但需要经常迭代,我建议使用本机 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,所以在它不起作用的地方为 IE填充https://github.com/es-shims/Object.entries 。

于 2016-10-03T10:22:10.237 回答
8

你可以使用map方法和forEach数组,但如果你想使用它,Object那么你可以像下面这样使用扭曲:

使用 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}
于 2018-09-29T12:03:26.867 回答
7

map function不存在,Object.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;
});
于 2013-02-11T10:51:04.640 回答
6

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

const identity = x =>
  x

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

o某个对象在哪里,f是您的映射功能。或者我们可以说,给定一个 from 的函数a -> b和一个值为 typea的对象,生成一个值为 type 的对象b。作为伪类型签名 -

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

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

  1. m,映射功能 – 让您有机会在...之前转换传入的元素
  2. r归约函数——这个函数将累加器与映射元素的结果相结合

直观地说,mapReduce创建一个新的 reducer,我们可以直接插入Array.prototype.reduce. 但更重要的是,我们可以omap通过使用对象 monoidObject.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]) })

这就是说,给定一个已知对象o和一些 key k,构造一个对象,其计算属性k是调用fkey 的值的结果o[k]

如果我们首先抽象出mapReduce的测序潜力oreduce

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

一切都一样,但omap现在可以在更高级别定义。当然,新的Object.entries让这看起来很傻,但练习对学习者来说仍然很重要。

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

于 2016-08-09T06:12:00.280 回答
3

我在谷歌搜索中第一个尝试学习如何做到这一点,并认为我会与其他人分享我最近找到的解决方案,该解决方案使用不可变的 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)”)以及其他一些 immutable-js 数据结构也可能非常有效地完成这项工作。

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

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

于 2018-01-07T22:02:46.197 回答
3

TypeScript 中的对象映射器

我喜欢这个使用的例子Object.fromEntries但是,它们仍然不是很容易使用。使用Object.keys然后查找的答案key实际上是在进行可能没有必要的多次查找。

我希望有一个Object.map函数,但我们可以创建自己的函数并调用它objectMap,并能够同时修改keyvalue

用法(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' }

代码(打字稿):

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 代码。

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

* 一些功劳归功于 alexander-mills 的回答

于 2019-08-13T23:37:25.267 回答
2

基于@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}
于 2016-02-02T13:30:08.270 回答
2

我的回复主要基于此处评分最高的回复,希望每个人都能理解(在我的 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])重新分配给想要的东西,而不是其他任何东西。据我所知,为了防止数组输出,必须重新分配图像[键],并且没有隐式或显式请求返回数组(变量赋值会这样做并且对我来说来回出现故障)。

编辑:

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

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),并在 mapFn( obj)[键],

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

并返回对结果执行的操作(位于 .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"}

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

于 2019-02-06T22:06:06.390 回答
2
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 属性可以删除

于 2019-10-18T21:25:58.800 回答
1

如果您map不仅对 ping 值感兴趣,而且对键感兴趣,我已经写过Object.map(valueMapper, keyMapper),它的行为方式如下:

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 }
于 2015-03-16T13:33:26.840 回答
1

我需要一个允许修改键的版本(基于@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);
}

事实对象=

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

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

于 2016-08-11T04:32:19.470 回答
1
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 }
于 2016-11-16T12:32:18.553 回答
1

为了更准确地响应OP 的要求,OP 需要一个对象:

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

有一个 map 方法myObject.map

类似于 Array.prototype.map ,其用法如下:

newObject = myObject.map(函数(值,标签){
    返回值*值;
});
// newObject 现在是 { '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;
}

一些东西,在仔细监督的情况下应该不会有任何不良影响,也不会影响map其他对象(即 Array's map)的方法。

于 2018-12-09T12:44:33.183 回答
1

首先,使用 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

于 2019-01-09T21:40:22.663 回答
1

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

Object.keys(params).map(k => typeof params[k] == "string" ? params[k] = params[k].trim() : null);
于 2019-08-06T09:17:44.813 回答
0

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

    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];
                }
              }
            }
         }
      }
于 2016-01-22T13:55:54.557 回答
0

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

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

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

于 2018-05-22T23:41:00.450 回答
0

另一种方法是使用自定义 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))

于 2018-07-31T15:21:04.323 回答
0

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

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}
于 2021-05-17T15:25:00.670 回答
-1

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

var mapped = [item].map(myMapFunction).pop();
于 2016-10-03T09:20:04.770 回答
-1

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

于 2020-04-28T15:45:50.023 回答
-1

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 }

于 2020-07-01T10:49:30.710 回答
-1

这是另一个版本,它允许映射函数根据当前键和值声明任意数量的新属性(键和值)。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" ]

于 2021-05-21T12:27:26.350 回答
-2

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() 转换 object

于 2018-04-09T11:12:31.717 回答
-2
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)
于 2019-03-01T20:49:55.970 回答
-2

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' ]
于 2019-05-31T03:26:26.540 回答
-2

使用以下地图函数来定义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);

于 2020-07-17T18:50:21.543 回答
-2

异步,有人吗?

尽管有大量评论,但我没有找到使用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)
);
于 2021-07-09T12:22:13.637 回答