Итерация по атрибутам объекта и их изменение

Underscore.js предоставляет _.each и _.map в коллекциях, что приятно, но мне нужно перебирать все атрибуты моего объекта. Мне нужно изменить значения и сохранить ключи. Например. У меня есть что-то вроде: {a:1, b:2, c:3}, и мне нужно выполнить операцию, которая изменяет значение, но сохраняет ключи. Скажем, я буду вычислять квадраты, я должен получить {a:1, b:4, c:9}. Вопрос в следующем: как это сделать с помощью подчеркивания (не интересуется javascript в vanilla)? Мне бы понравился такой метод, как:

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

Кроме того, было бы здорово, если бы было возможно связать его, так как я делаю карту, дамп-результат для выполнения каждого, а затем снова использую карту (потому что мне нужно).

Ответы

Ответ 1

Я немного посмотрел на некоторые из моих фрагментов, чтобы узнать, есть ли возможность изменить исходный объект, но я не нашел ничего интересного, поэтому я бы пошел с this:\

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

Я надеюсь, что там будет более элегантное решение.

Ответ 2

_.mapObject (добавлено в версии 1.8) именно то, что вы ищете.


Для предыдущих версий, можно мутировать исходный объект, используя третий аргумент для обратного вызова _.each.

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

Использование _.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;
        }, {});
    }
});

Ответ 3

Как сказал Джастин _. mapObject может быть тем, что вы искали. Но создает новый объект (расширяющий {}), который может быть не таким, каким вы хотите (например, если это не простой объект, например new THREE.Vector3()), здесь нехорошо заменить оригинальный объект что-то другое.

В этом случае (изменяя значения на месте в данном объекте) просто используйте _. каждый с третьим параметром вашей итерационной функции:

_.each(complexObject, function(value, key, obj) {
  obj[key] = value * value;
}); 

Ответ 4

Большое спасибо 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).