Итерация по атрибутам объекта и их изменение
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
).