对象的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,所以我不关心跨浏览器的问题。)

2321172 次浏览

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

写一个很容易:

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的现有属性发生冲突。

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

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 }

#0通过将前一个值与当前值合并来将数组减少为一个值。链由一个空对象{}初始化。在每次迭代中,都会添加一个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)) 

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

没有本地方法,但Ladash#mapValue应用场景将出色地完成这项工作

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

如果你对mapping不仅对值而且对键感兴趣,我写了#1,它的行为是这样的:

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 }

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

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

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

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

    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];}}}}}

基于@Amberlight的回答,这里有一个效用函数(看起来很丑)

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}

接受的答案有两个缺点:

  • 它误用了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); // Amap(x => o[x] = f(o[x])) (keys(o)); // Breturn 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的浅表副本。我们现在能够在omap内突变o,而无需在父范围内突变o
  • 在B行map的返回值被忽略,因为map执行了o的突变。由于此副作用保持在omap内并且在父作用域中不可见,因此完全可以接受。

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

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

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

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

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

使用#0#1

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,但您可以使用#1结合点差运算符计算键名语法来实现相同的目的:

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

ES6/ES2015不允许Object.entries,但您可以使用#1代替:

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

ES6还引入了#0循环,允许更多当务之急风格:

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


array.reduce()

除了Object.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 obj2console.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'}

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

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

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

其中o是某个对象,f是您的映射函数。或者我们可以说,给定a -> b中的一个函数,以及一个具有a类型值的对象,生成一个具有b类型值的对象。作为伪类型签名-

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

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

  1. m映射函数-让您有机会在…之前转换传入元素。
  2. r减少函数-此函数将累加器与映射元素的结果相结合

直观地说,mapReduce创建了一个新的简化器,我们可以直接插入Array.prototype.reduce。但更重要的是,我们可以通过使用对象单半群、Object.assign{}来简单地实现我们的对象仿函数实现omap

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和某个键k,构造一个对象,其计算属性k是对键的值o[k]调用f的结果。

如果我们首先抽象出oreduce,我们可以瞥见mapReduce的测序潜力

// 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的全部潜力,但我分享这个答案,因为看看它可以应用在多少地方是很有趣的。如果你对它是如何派生的以及它可能有用的其他方式感兴趣,请参阅这个答案

我需要一个允许修改密钥的版本(基于@Amberlight和@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"}}

编辑:传递起始对象{}的轻微更改。允许它是[](如果键是整数)

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

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

为了最大的性能。

如果您的对象不经常更改,但需要经常迭代,我建议使用本机Map作为缓存。

// example objectvar obj = {a: 1, b: 2, c: 'something'};
// caching mapvar objMap = new Map(Object.entries(obj));
// fast iteration on Map objectobjMap.forEach((item, key) => {// do something with an itemconsole.log(key, item);});

Object.entries已经可以在Chrome,Edge,Firefox和beta Opera中使用,因此它是一个面向未来的功能。它来自ES7,所以在IE中它不起作用的地方,它是https://github.com/es-shims/Object.entries

这真的很烦人,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;});

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

Object.map = ... // fairly safeObject.prototype.map ... // not ok
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 }

最小版本

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

我在谷歌搜索中发现了这一点,试图学习做到这一点,并认为我将分享最近我发现的解决方案,该解决方案使用npm包不可变。

我认为分享它很有趣,因为不可变在他们自己的留档中使用OP的精确情况-以下不是我自己的代码,而是从当前的不可变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/

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>

Use new _.transform() to transforms object.

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

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

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

对它的另一种看法是使用自定义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))

你可以在数组上使用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}

为了更紧密地响应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 }

imho最佳(以“接近所要求的”+“不需要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的map)。

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

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

参考https://medium.com/@js_tut

我的回复主要基于这里评分最高的回复,希望每个人都能理解(在我的GitHub上也有同样的解释)。这就是为什么他对地图的影响有效:

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

该函数的目的是使用所有对象(对象和数组都一样)可用的方法获取一个对象并修改该对象的原始内容,而不返回数组。JS中几乎所有内容都是对象,因此继承管道中更远的元素在技术上可能会使用在线上的元素可用的元素(看起来相反)。

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

这个特定的程序接受一个名为图像的对象,并接受其键的值并附加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')};

对象的原始结构保持不变,允许正常的属性访问,只要没有返回。不要让它像正常一样返回数组,一切都会好起来的。目标是将原始值(图像[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),并简单地返回存储在mapFn(obj)[key]中的该键的值(或者如果您像他一样更改返回值,则乘以2),

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

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

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

{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函数中的值来复制任何对象。

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)

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.fromEntries将数组转换回对象。

这种模式很酷的一点是,您现在可以在映射时轻松考虑对象键。

需求文档

浏览器支持

Object.fromEntries目前仅受这些浏览器/引擎支持,但也有可用的Poly填充(例如@杨辉)。

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

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

Object.keys(params).map(k => typeof params[k] == "string" ? params[k] = params[k].trim() : null);

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 valuelet obj = objectMap(myObject, val => val * 2);// obj = { a: 2, b: 4, c: 6 }

// modify both key and valueobj = 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代码。

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

*一些信贷去亚历山大-米尔斯回答

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

此函数递归遍历对象和对象数组。如果返回未定义,可以删除属性

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

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

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

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

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 }

使用以下map函数定义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 questionnewObject = myObject.map(function (value, label) {return  value * value;});
console.log(newObject);

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

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

使用。传递一个键映射器和一个值映射器函数:

const o1 = { x: 1, c: 2 }mappedObject(o1, k => k + '0', v => v + 1) // {x0: 2, c0: 3}

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

异步,有人吗?

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

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

(注意没有选项传递给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));