Сделать Javascript do List понимание
каков самый чистый способ заставить Javascript сделать что-то как понимание списка Python?
в Python если у меня есть список объектов, чье имя я хочу "вытащить", я бы это сделал...
list_of_names = [x.name for x in list_of_objects]
в javascript я действительно не вижу более "красивого" способа сделать это, кроме как просто использовать конструкцию цикла for.
FYI: я использую jQuery; может быть, у него есть какая-то отличная функция, которая делает это возможным?
больше в частности, скажем, я использую селектор jQuery, например $('input')
для всех input
элементы, как бы я самых чистоплотных создать массив всех name
атрибуты для каждого из этих input
элементы, т. е. все $('input').attr('name')
строки в массиве?
10 ответов:
общий случай с помощью массив.карта, требуется javascript 1.6 (что означает, работает на каждом браузере, но IE или С объектом дополняя рамки, как 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
ошибаются; не сам код, но реализации являются неоптимальными.Edit: там же выделения массива введено в Javascript 1.7, но это чисто зависит от синтаксиса и не может быть эмулировано в браузерах, которые не имеют его изначально. Это самое близкое, что вы можете получить в Javascript к фрагменту Python, который вы опубликовали.
понимание списка имеет несколько частей к нему.
- выбор набора чего-то
- из набора чего-то
- фильтруется чем-то
в 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
.
те, кто интересуется "красивым" Javascript, вероятно, должны проверить CoffeeScript язык, который компилируется в JavaScript. Он по существу существует, потому что Javascript не хватает таких вещей, как понимание списка.
в частности, понимание списка в CoffeeScript является даже более гибким, чем в Python. Вижу список документов для понимания здесь.
например, этот код приведет к массиву
name
атрибутыinput
элементы.потенциальный недостаток-результирующий JavaScript подробного (и ИМХО толку):[$(inp).attr('name') for inp in $('input')]
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; })() ];
Итак, понимание списка python на самом деле делает две вещи сразу: отображение и фильтрацию. Например:
list_of_names = [x.name for x in list_of_object if x.enabled]
Если вам просто нужна часть отображения, как показывает ваш пример, вы можете использовать функцию карты jQuery. Если вам также нужна фильтрация, вы можете использовать функцию "grep" jQuery.
многоразовый способ сделать это-создать крошечный плагин 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 для того, что это хорошо.
понимание массива является частью проекта ECMAScript 6. В настоящее время (январь 2014) их реализует только JavaScript Mozilla/Firefox.
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 недавно переключился на синтаксис слева направо, похожий на C# и F#:
var squares = [for (i of numbers) i*i]; // => [1,4,9,16]
http://kangax.github.io/es5-compat-table/es6/#Array_comprehensions
Да-я тоже скучаю по списку понимания.
вот ответ, который немного менее подробный, чем ответ @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(',');
существует однострочный подход, он включает в себя использование вложенной функции закрытия в конструктор списка. И функция, которая идет долго с ним, чтобы генерировать последовательность. Его определяют ниже:
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]
хотя это решение не является самым чистым, оно выполняет свою работу. И в производстве я бы наверное, не советую этого делать.
наконец, можно выбрать не использовать рекурсию для моего метода "generate", поскольку это сделает работу быстрее. Или даже лучше использовать встроенную функцию из многих популярных библиотек 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; }))];
синтаксис отстой я знаю!
удачи.
Это пример места, где 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; })() ];
С помощью jQuery
.each()
функция, вы можете перебирать каждый элемент, получить индекс текущего элемента и, используя этот индекс, вы можете добавить атрибут name вlist_of_names
массив...var list_of_names = new Array(); $('input').each(function(index){ list_of_names[index] = $(this).attr('name'); });
хотя это по существу метод цикла, который вы указали, что вы не хотите, это невероятно аккуратная реализация цикла и позволяет запускать цикл на определенных селекторах.
надеюсь, что это поможет:)