可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
The map
function in underscore.js, if called with a javascript object, returns an array of values mapped from the object's values.
_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; });
=> [3, 6, 9]
is there a way to make it preserve the keys? ie, I want a function that returns
{one: 3, two: 6, three: 9}
回答1:
With Underscore
Underscore provides a function _.mapObject
to map the values and preserve the keys.
_.mapObject({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; });
// => { one: 3, two: 6, three: 9 }
DEMO
With Lodash
Lodash provides a function _.mapValues
to map the values and preserve the keys.
_.mapValues({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; });
// => { one: 3, two: 6, three: 9 }
DEMO
回答2:
I managed to find the required function in lodash, a utility library similar to underscore.
http://lodash.com/docs#mapValues
_.mapValues(object, [callback=identity], [thisArg])
Creates an object with the same keys as object and values generated by
running each own enumerable property of object through the callback.
The callback is bound to thisArg and invoked with three arguments;
(value, key, object).
回答3:
var mapped = _.reduce({ one: 1, two: 2, three: 3 }, function(obj, val, key) {
obj[key] = val*3;
return obj;
}, {});
console.log(mapped);
<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
回答4:
I know this is old, but now Underscore has a new map for objects :
_.mapObject(object, iteratee, [context])
You can of course build a flexible map for both arrays and objects
_.fmap = function(arrayOrObject, fn, context){
if(this.isArray(arrayOrObject))
return _.map(arrayOrObject, fn, context);
else
return _.mapObject(arrayOrObject, fn, context);
}
回答5:
How about this version in plain JS (ES6 / ES2015)?
let newObj = Object.assign(...Object.keys(obj).map(k => ({[k]: obj[k] * 3})));
jsbin
If you want to map over an object recursively (map nested obj), it can be done like this:
const mapObjRecursive = (obj) => {
Object.keys(obj).forEach(key => {
if (typeof obj[key] === 'object') obj[key] = mapObjRecursive(obj[key]);
else obj[key] = obj[key] * 3;
});
return obj;
};
jsbin
Since ES7 / ES2016 you can use Object.entries
instead of Object.keys
like this:
let newObj = Object.assign(...Object.entries(obj).map([k, v] => ({[k]: v * 3})));
回答6:
_.map returns an Array, not an Object.
If you want an object you're better off using a different function, like each
; if you really want to use map you could do something like this:
Object.keys(object).map(function(value, index) {
object[value] *= 3;
})
but that is confusing, when seeing map
one would expect to have an array as result and then make something with it.
回答7:
I think you want a mapValues function (to map a function over the values of an object), which is easy enough to implement yourself:
mapValues = function(obj, f) {
var k, result, v;
result = {};
for (k in obj) {
v = obj[k];
result[k] = f(v);
}
return result;
};
回答8:
I know it's been a long time, but still the most obvious solution via fold (aka reduce in js) is missing, for the sake of completeness i'll leave it here:
function mapO(f, o) {
return Object.keys(o).reduce((acc, key) => {
acc[key] = f(o[key])
return acc
}, {})
}
回答9:
A mix fix for the underscore map bug :P
_.mixin({
mapobj : function( obj, iteratee, context ) {
if (obj == null) return [];
iteratee = _.iteratee(iteratee, context);
var keys = obj.length !== +obj.length && _.keys(obj),
length = (keys || obj).length,
results = {},
currentKey;
for (var index = 0; index < length; index++) {
currentKey = keys ? keys[index] : index;
results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
}
if ( _.isObject( obj ) ) {
return _.object( results ) ;
}
return results;
}
});
A simple workaround that keeps the right key and return as object
It is still used the same way as i guest you could used this function
to override the bugy _.map function
or simply as me used it as a mixin
_.mapobj ( options , function( val, key, list )
回答10:
You can use _.mapValues(users, function(o) { return o.age; });
in Lodash and _.mapObject({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; });
in Underscore.
Check out the cross-documentation here: http://jonathanpchen.com/underdash-api/#mapvalues-object-iteratee-identity