Подтвердить что ты не робот

Сделать 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') в массиве?

4b9b3361

Ответ 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');
});

Хотя это, по сути, метод цикла, который вы указали не хотите, это невероятно реалистичная реализация цикла и позволяет запускать цикл для определенных селекторов.

Надеюсь, что помогает:)