遍历对象属性并修改它们

25

Underscore.js提供了对集合的_.each_.map进行迭代,这很好,但我需要遍历我的对象的所有属性。我需要修改值并保留键。例如,我有一个类似于{a:1, b:2, c:3}的东西,我需要执行一个操作,改变值但保持键不变。比如说,我要计算平方,我应该得到{a:1, b:4, c:9}。问题是:如何使用underscore来做到这一点(不考虑原生JavaScript)?我希望有一个像这样的方法:

var a = {a:1, b:2, c:3}
_.magic(a, function(item){ return item*item; });

另外,如果可以将其链接起来就更好了,因为我正在进行映射、转储结果以执行每一个操作,然后再次使用映射(因为我需要这么做)。

4个回答

40

_.mapObject自1.8版本添加)正是您所寻找的。


对于以前的版本,可以使用_.each回调的第三个参数来改变原始对象。

_.each({a:1, b:2, c:3}, function(value, key, obj) { obj[key] = value * value; });

使用带有初始 memo 的 _.reduce 也可以创建全新的对象。

_.reduce({a:1, b:2, c:3}, function(memo, value, key) {
    memo[key] = value * value;
    return memo;
}, {});

我更喜欢使用_.reduce方法。一个简单的mixin可以使它的行为与_.map完全一致。

_.mixin({
    magic: function(obj, iterator, context) {
        return _.reduce(obj, function(memo, value, key) {
            memo[key] = iterator.call(context, value, key, obj);
            return memo;
        }, {});
    }
});

19

我进一步研究了我的一些代码片段,看看是否有选项可以改变原始对象,但我没有找到任何有趣的内容,因此我将采用这个

var original = {a:1, b:2, c:3};
var squaredValues = _.object(_.map(original, function (value, key) {
    return [key, value * value];
}));

我希望有一个更优雅的解决方案。


7
作为Justin所说的,_.mapObject可能是你正在寻找的。但是,这会创建一个新对象(扩展{}),这可能不是你想要的(例如,如果它不是像new THREE.Vector3()这样的简单对象),在这种情况下,用不好将原始对象替换为不同的东西。
对于这种情况(在给定对象中就地修改值),只需使用_.each和迭代器函数的第三个参数即可。
_.each(complexObject, function(value, key, obj) {
  obj[key] = value * value;
}); 

1
感谢Javier92指出了正确的解决方案。
无论如何,我不喜欢使用使用另外两个下划线方法的下划线方法(不太可读),因此我想出了一个简单的包装函数,将其混合到下划线中:
// mixin to make our new function available via _
_.mixin({
    updateAttributes: function(object, iteratee) {
        return _.object(_.map(object, function (value, key) {
            return [key, iteratee(value)];
        }));
    }
});

在你的代码中某处使用它:

_.updateAttributes({a:1, b:2, c:3}, function(item){ return item*item; })
// Object {a: 1, b: 4, c: 9}

我想不出一个单词的函数名(可能有比updateAttributes更好的选择)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接