让JavaScript支持列表推导式

68 投票
11 回答
31521 浏览
提问于 2025-04-16 11:36

怎样才能让JavaScript做一些像Python的列表推导那样的事情,最简单的方法是什么呢?

在Python中,如果我有一个对象列表,想要提取它们的名字,我会这样做……

list_of_names = [x.name for x in list_of_objects]

在JavaScript中,我觉得除了用for循环之外,没有更“优雅”的方法来实现这个。

顺便说一下,我在使用jQuery;也许它有一些很酷的功能可以做到这一点?

更具体地说,假设我使用jQuery选择器像 $('input') 来获取所有的 input 元素,我该如何最“干净”地创建一个数组,包含这些 input 元素的所有 name 属性——也就是说,如何把所有的 $('input').attr('name') 字符串放到一个数组里?

11 个回答

6

对“美丽”的Javascript感兴趣的人可以看看CoffeeScript,这是一种可以转换成Javascript的编程语言。它的出现主要是因为Javascript缺少一些功能,比如列表推导。

特别是,CoffeeScript的列表推导比Python的还要灵活。你可以在这里查看列表推导的文档

举个例子,这段代码会生成一个包含所有元素的name属性的数组。

[$(inp).attr('name') for inp in $('input')]

不过一个潜在的缺点是,生成的Javascript代码比较冗长(而且在我看来有点让人困惑):

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;
  })()
];
12

列表推导式有几个部分。

  1. 选择一组东西
  2. 从一组东西中
  3. 通过某种条件筛选

在JavaScript中,从ES5开始(这意味着IE9及以上版本、Chrome和Firefox都支持),你可以在数组上使用 mapfilter 函数。

你可以用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

56

这里讲的是一个通用的案例,使用了Array.map,这个功能需要JavaScript 1.6(也就是说,除了IE 9以下的浏览器,其他浏览器都能用)。如果你用的是像MooTools这样的框架,它在所有浏览器上都能工作:

var list_of_names = document.getElementsByTagName('input').map(
  function(element) { return element.getAttribute('name'); }
);

如果你在处理一个没有提供map功能的可迭代对象(比如生成器),你可以使用扩展语法,先把它变成一个数组:

[...Array(10).keys()].map(x => x * 2 + 3)

扩展语法也可以用在数组上,所以如果你需要对任何可迭代对象使用map,最好先把它展开成一个列表。

(注意这个例子还用了箭头函数,这需要支持ES6的浏览器。大多数浏览器版本要么支持这两者,要么都不支持。如果需要支持IE,它自己又不支持这两者,不过IE已经被Edge替代一段时间了。)

这是一个特定于jQuery的例子,适用于所有浏览器:

var list_of_names = jQuery.map(jQuery('input'), function(element) { return jQuery(element).attr('name'); });

其他答案中使用.each的方法是不对的;不是代码本身有问题,而是实现方式不够优化。

编辑:还有在JavaScript 1.7中引入的数组推导,但这完全依赖于语法,不能在没有原生支持的浏览器上模拟。这是JavaScript中最接近你发布的Python代码的东西。不过,这个已经从语言中移除了

撰写回答