映射函数的对象(而不是数组)
我有一个对象:
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
function? (我想要这个Node.JS,所以我不关心跨浏览器的问题。)
Object
对象没有本地map
,但是这个如何:
Object.keys(myObject).map(function(key, index) { myObject[key] *= 2; }); console.log(myObject); // => { 'a': 2, 'b': 4, 'c': 6 }
但是你可以很容易地迭代一个对象使用for ... in
:
for(var key in myObject) { if(myObject.hasOwnProperty(key)) { myObject[key] *= 2; } }
更新
很多人都提到,以前的方法不会返回一个新的对象,而是对对象本身进行操作。 对于这个问题,我想添加另一个解决scheme,返回一个新的对象,并保持原来的对象,因为它是:
var newObject = Object.keys(myObject).reduce(function(previous, current) { previous[current] = myObject[current] * myObject[current]; return previous; }, {}); console.log(newObject); // => { 'a': 1, 'b': 4, 'c': 9 } console.log(myObject); // => { 'a': 1, 'b': 2, 'c': 3 }
Array.prototype.reduce
通过将前一个值与当前值相结合,将数组减less为单个值。 链由空对象{}
初始化。 在每次迭代中, myObject
的新密钥都以其平方值作为值添加。
没有本地方法,但lodash#mapValues将做出出色的工作
_.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; }); // → { 'a': 3, 'b': 6, 'c': 9 }
如何在简单的JS( ES6 / ES2015 )即时variables赋值的单线程 ?
使用扩展运算符和计算键名称语法:
let newObj = Object.assign({}, ...Object.keys(obj).map(k => ({[k]: obj[k] * obj[k]})));
jsbin
另一个版本使用reduce:
let newObj = Object.keys(obj).reduce((p, c) => ({...p, [c]: obj[c] * obj[c]}), {});
jsbin
作为函数的第一个例子:
const oMap = (o, f) => Object.assign(...Object.keys(o).map(k => ({ [k]: f(o[k]) }))); // To square each value you can call it like this: let mappedObj = oMap(myObj, (x) => x * x);
jsbin
如果您想以function样式recursion地映射嵌套对象,可以这样做:
const sqrObjRecursive = (obj) => Object.keys(obj).reduce((newObj, key) => (obj[key] && typeof obj[key] === 'object') ? {...newObj, [key]: sqrObjRecursive(obj[key])} : // recurse. {...newObj, [key]: obj[key] * obj[key]} // square val. ,{})
jsbin
更重要的是,像这样:
const sqrObjRecursive = (obj) => { Object.keys(obj).forEach(key => { if (typeof obj[key] === 'object') obj[key] = sqrObjRecursive(obj[key]); else obj[key] = obj[key] * obj[key] }); return obj; };
jsbin
由于ES7 / ES2016可以使用Object.entries
而不是Object.keys
例如:
let newObj = Object.assign(...Object.entries(obj).map(([k, v]) => ({[k]: v * v})));
inheritance的属性和原型链:
在一些罕见的情况下,您可能需要映射一个类对象, 该类对象在其原型链上保存了一个inheritance对象的属性。 在这种情况下, Object.keys()
将不起作用,因为Object.keys()
不枚举inheritance的属性。 如果你需要映射inheritance的属性,你应该使用for (key in myObj) {...}
。
下面是一个inheritance另一个对象属性的对象的例子,以及Object.keys()
在这种情况下不起作用的例子。
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. for (key in obj2) { console.log(key); // Prints: 'a', 'b', 'c' }
jsbin
但是,请帮我一个忙,避免inheritance 。 🙂
写一个很容易:
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 }
注意:这个版本还允许你(可选地)为callback设置this
上下文,就像Array
方法一样。
编辑 – 更改为删除使用Object.prototype
,以确保它不与任何现有属性名为map
上的对象冲突。
您可以使用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
检查。
我来到这里寻找和回答映射一个对象到一个数组,并得到这个页面作为结果。 如果你来到这里寻找同样的答案,那么这里是你如何映射和对象到一个数组。
你可以使用map从对象返回一个新的数组,像这样:
var newObject = Object.keys(myObject).map(function(key) { return myObject[key]; });
被接受的答案有两个缺点:
- 它滥用
Array.prototype.reduce
,因为减less意味着改变一个复合types的结构,在这种情况下不会发生。 - 它不是特别可重用的
ES6 / ES2015function方法
请注意,所有function都以咖啡forms定义。
// 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));
这是简单的,JS社区里的每个人都知道。 应该有这个function:
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){ const ret = {}; Object.keys(obj).forEach(function(k){ ret[k] = fn.call(null,k,obj[k]); }); return ret; };
这是非常烦人的,必须自己实现这一点;)
为了获得最佳性能
如果您的对象不经常更改,但需要经常迭代,我build议使用本地映射作为caching。
// 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); });
为什么不在戒指里戴另一顶帽子?
// pair :: (a,b) -> Pair const pair = (x,y) => [x,y] // keys :: Object(k:a) -> [k] const keys = Object.keys // oreduce :: (a -> Pair(k,b) -> a) -> a -> Object(k:b) -> a const oreduce = f => acc => o => { let loop = (acc, [k,...ks]) => k === undefined ? acc : loop (f (acc) (pair (k, o[k])), ks) return loop (acc, keys (o)) } // omap :: (Pair(k,a) -> b) -> Object(k:a) -> Object(k:b) const omap = f => oreduce (acc => ([k,v]) => Object.assign(acc, { [k]: f(v) }) ) ({}) // pairs :: Object(k:a) -> [Pair(k,a)] const pairs = oreduce(acc=> pair=> [...acc, pair]) ([]) // DEMONSTRATION let o = {a: 1, b: 2, c: 3} console.log(omap (x => x * 3) (o)) // => { a: 3, b: 6, c: 9 } console.log(oreduce (s=> ([k,v])=> s + `&${k}=${v}`) ('?') (o)) // => ?&a=1&b=2&c=3 console.log(pairs(o)) // => [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]
基于@Amberlamps答案,这里是一个实用function(作为一个看起来丑陋的评论)
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}
最小版本(es6):
Object.entries(obj).reduce((a, [k, v]) => (a[k] = v * v, a), {})
Object.prototype
上的map function
不存在,但是您可以像这样模拟它
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; });
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 }
如果你对map
ping不仅Object.map(valueMapper, keyMapper)
而且对键也有兴趣,我写了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 }
嗨写了一个小的mapper函数可能会有所帮助。
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]; } } } } }
我需要一个允许修改密钥的版本(基于@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"} }
编辑:稍微改变,传入起始对象{}。 允许它是[](如果键是整数)
我特别想使用与单个对象的数组相同的function,并希望保持简单。 这对我工作:
var mapped = [item].map(myMapFunction).pop();
我知道这是一个古老的问题,但其中一些答案太长而且复杂。
您可以通过有序对使用简单的for-in循环。 下面的代码适合你的数组对象。 hasOwnProperty()
是因为您为对象创build了三个属性(包含值)。
var myObject = { 'a': 1, 'b': 2, 'c': 3 } function getValue(key) { for (var k in myObject ) { if (myObject.hasOwnProperty(key)) { return myObject[key]; } } }
Input: <input id="input" value="" placeholder="a, b or c"><br> Output:<input id="output"><br> <button onclick="output.value=getValue(input.value)" >Get value</button>