Сделать Javascript выполнимым списком
Каков самый чистый способ заставить Javascript сделать что-то вроде понимания списка Python?
В Python, если у меня есть список объектов, имя которых я хочу "вытащить", я бы сделал это...
list_of_names = [x.name for x in list_of_objects]
В javascript я действительно не вижу более "красивого" способа сделать это иначе, чем просто использовать конструкцию for loop.
FYI: Я использую jQuery; возможно, у него есть отличная функция, которая делает это возможным?
В частности, скажем, я использую селектор jQuery, такой как $('input')
, чтобы получить все элементы input
, как бы я мог максимально создать массив из всех атрибутов name
для каждого из этих элементов input
- т.е., все строки $('input').attr('name')
в массиве?
Ответы
Ответ 1
Общий аргумент с использованием Array.map требует, чтобы javascript 1.6 (это значит, работает в каждом браузере, но IE и 9), или с помощью расширяющей объект инфраструктуры, такой как MooTools в каждом браузере:
var list_of_names = document.getElementsByTagName('input').map(
function(element) { return element.getAttribute('name'); }
);
Специальный пример jQuery работает в каждом браузере:
var list_of_names = jQuery.map(jQuery('input'), function(element) { return jQuery(element).attr('name'); });
другие ответы с использованием .each
неверны; а не сам код, но реализации субоптимальные.
Изменить: там также Массивные представления, представленные в Javascript 1.7, но это зависит исключительно от синтаксиса и не может эмулироваться в браузерах, которые не имеют это изначально. Это самая близкая вещь, которую вы можете получить в Javascript в опубликованном вами фрагменте Python.
Ответ 2
У понимания списка есть несколько частей.
- Выбор набора
- Из набора Something
- Filtered by Something
В JavaScript, как и в ES5 (поэтому я думаю, что поддерживается в IE9 +, Chrome и FF), вы можете использовать функции map
и filter
для массива.
Вы можете сделать это с помощью карты и фильтра:
var list = [1,2,3,4,5].filter(function(x){ return x < 4; })
.map(function(x) { return 'foo ' + x; });
console.log(list); //["foo 1", "foo 2", "foo 3"]
Это примерно так же хорошо, как и без дополнительных методов или с использованием другой структуры.
Что касается конкретного вопроса...
С jQuery:
$('input').map(function(i, x) { return x.name; });
Без jQuery:
var inputs = [].slice.call(document.getElementsByTagName('input'), 0),
names = inputs.map(function(x) { return x.name; });
[].slice.call()
- это просто преобразовать NodeList
в Array
.
Ответ 3
Те, кто интересуется "красивым" Javascript, должны, вероятно, проверить CoffeeScript, язык, который компилируется в Javascript. Он по существу существует, потому что в Javascript отсутствуют такие вещи, как понимание списка.
В частности, понимание списка Coffeescript еще более гибкое, чем Python. Подробнее см. список.
Например, этот код приведет к массиву атрибутов name
элементов input
.
[$(inp).attr('name') for inp in $('input')]
Потенциальный недостаток, однако, является результатом Javascript многословным (и IMHO запутанным):
var inp;
[
(function() {
var _i, _len, _ref, _results;
_ref = $('input');
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
inp = _ref[_i];
_results.push($(inp).attr('name'));
}
return _results;
})()
];
Ответ 4
Итак, на основе списков python на самом деле делают сразу две вещи: отображение и фильтрацию. Например:
list_of_names = [x.name for x in list_of_object if x.enabled]
Если вам просто нужна часть отображения, как показывает ваш пример, вы можете использовать функцию карты jQuery. Если вам также нужна фильтрация, вы можете использовать функцию jQuery "grep".
Ответ 5
Повторяемый способ сделать это - создать крошечный плагин jQuery следующим образом:
jQuery.fn.getArrayOfNames = function() {
var arr = [];
this.each( function() { arr.push(this.name || ''); } );
return arr;
};
Затем вы можете использовать его следующим образом:
var list_of_names = $('input').getArrayOfNames();
Это не список понимания, но это не существует в javascript. Все, что вы можете сделать, это использовать javascript и jquery для того, для чего это полезно.
Ответ 6
Массивные представления являются частью проекта ECMAScript 6. В настоящее время (январь 2014) только Mozilla/Firefox JavaScript реализует их.
var numbers = [1,2,3,4];
var squares = [i*i for (i of numbers)]; // => [1,4,9,16]
var somesquares = [i*i for (i of numbers) if (i > 2)]; // => [9,16]
Хотя ECMAScript 6 недавно переключился на синтаксис слева направо, похожий на С# и F #:
var squares = [for (i of numbers) i*i]; // => [1,4,9,16]
http://kangax.github.io/es5-compat-table/es6/#Array_comprehensions
Ответ 7
Да, я тоже скучаю по спискам.
Здесь ответ, который немного менее подробный, чем @gonchuki, отвечает и преобразует его в фактический массив, а не в тип объекта.
var list_of_names = $('input').map(function() {
return $(this).attr('name');
}).toArray();
В этом случае все флажки отмечены и присоединяются к хэшу URL-адреса, например:
window.location.hash = $('input:checked').map(function() {
return $(this).attr('id');
}).toArray().join(',');
Ответ 8
Существует однострочный подход, он включает использование вложенной функции закрытия в
конструктор списка. И функция, которая длится с ней, чтобы сгенерировать последовательность.
Его определение ниже:
var __ = generate = function(initial, max, list, comparision) {
if (comparision(initial))
list.push(initial);
return (initial += 1) == max + 1 ? list : __(initial, max, list, comparision);
};
[(function(l){ return l; })(__(0, 30, [], function(x) { return x > 10; }))];
// returns Array[20]
var val = 16;
[(function(l){ return l; })(__(0, 30, [], function(x) { return x % val == 4; }))];
// returns Array[2]
Это реализация на основе диапазона, такая как диапазон Python (min, max)
Кроме того, понимание этого списка выглядит следующим образом:
[{closure function}({generator function})];
несколько тестов:
var alist = [(function(l){ return l; })(__(0, 30, [], function(x) { return x > 10; }))];
var alist2 = [(function(l){ return l; })(__(0, 1000, [], function(x) { return x > 10; }))];
// returns Array[990]
var alist3 = [(function(l){ return l; })(__(40, 1000, [], function(x) { return x > 10; }))];
var threshold = 30*2;
var alist3 = [(function(l){ return l; })(__(0, 65, [], function(x) { return x > threshold; }))];
// returns Array[5]
Хотя это решение не является самым чистым, он выполняет свою работу. И в производстве я бы, вероятно, советовал ему.
Наконец, вы можете отказаться от использования рекурсии для моего метода генерации, поскольку это ускорит работу. Или даже лучше использовать встроенную функцию из множества популярных Javascript-библиотек. Вот перегруженная реализация, которая также будет учитывать свойства объекта
// A list generator overload implementation for
// objects and ranges based on the arity of the function.
// For example [(function(l){ return l; })(__(0, 30, [], function(x) { return x > 10; }))]
// will use the first implementation, while
// [(function(l){ return l; })(__(objects, 'name', [], function(x, y) { var x = x || {}; return x[y] }))];
// will use the second.
var __ = generator = function(options) {
return arguments.length == 4 ?
// A range based implemention, modeled after pythons range(0, 100)
(function (initial, max, list, comparision) {
var initial = arguments[0], max = arguments[1], list = arguments[2], comparision = arguments[3];
if (comparision(initial))
list.push(initial);
return (initial += 1) == max + 1 ? list : __(initial, max, list, comparision);
})(arguments[0], arguments[1], arguments[2], arguments[3]):
// An object based based implementation.
(function (object, key, list, check, acc) {
var object = arguments[0], key = arguments[1], list = arguments[2], check = arguments[3], acc = arguments[4];
acc = acc || 0;
if (check(object[acc], key))
list.push(object[acc][key]);
return (acc += 1) == list.length + 1 ? list : __(object, key, list, check, acc);
})(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
};
Использование:
var threshold = 10;
[(function(l){ return l; })(__(0, 65, [], function(x) { return x > threshold; }))];
// returns Array[5] -> 60, 61, 62, 63, 64, 65
var objects = [{'name': 'joe'}, {'name': 'jack'}];
[(function(l){ return l; })(__(objects, 'name', [], function(x, y) { var x = x || {}; return x[y] }))];
// returns Array[1] -> ['Joe', 'Jack']
[(function(l){ return l; })(__(0, 300, [], function(x) { return x > 10; }))];
Синтаксис сосет, я знаю!
Желаем удачи.
Ответ 9
Это пример того места, где Coffeescript действительно сияет
pows = [x**2 for x in foo_arr]
list_of_names = [x.name for x in list_of_objects]
Эквивалентным Javascript будет:
var list_of_names, pows, x;
pows = [
(function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = foo_arr.length; _i < _len; _i++) {
x = foo_arr[_i];
_results.push(Math.pow(x, 2));
}
return _results;
})()
];
list_of_names = [
(function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = list_of_objects.length; _i < _len; _i++) {
x = list_of_objects[_i];
_results.push(x.name);
}
return _results;
})()
];
Ответ 10
Используя функцию jQuery .each()
, вы можете прокручивать каждый элемент, получать индекс текущего элемента и использовать этот индекс, вы можете добавить атрибут name в массив list_of_names
...
var list_of_names = new Array();
$('input').each(function(index){
list_of_names[index] = $(this).attr('name');
});
Хотя это, по сути, метод цикла, который вы указали не хотите, это невероятно реалистичная реализация цикла и позволяет запускать цикл для определенных селекторов.
Надеюсь, что помогает:)