代码之家  ›  专栏  ›  技术社区  ›  Martin Staufcik

空数组[]上的Javascript forEach.forEach.call[重复]

  •  0
  • Martin Staufcik  · 技术社区  · 5 年前

    例如,我有这样的东西:

    [].forEach.call( document.querySelectorAll('a'), function(el) {
       // whatever with the current node
    });
    

    但我不明白它是怎么工作的。谁能解释一下forEach前面的空数组的行为以及 call 作品?

    0 回复  |  直到 11 年前
        1
  •  220
  •   LetterEh    11 年前

    [] 是一个数组。
    这个数组根本不用。

    它被放到页面上,因为使用数组可以访问数组原型,比如 .forEach .

    Array.prototype.forEach.call(...);

    接下来, forEach 是一个以函数作为输入的函数。。。

    [1,2,3].forEach(function (num) { console.log(num); });
    

    …对于每个元素 this (其中 length this[1] )它将通过三件事:

    1. 数组中的元素
    2. 元素的索引(第三个元素将通过 2 )
    3. 对数组的引用

    最后, .call
    将接受其第一个参数并替换 call ,作为第一个参数( undefined null window 在每天的JS中,或将是你通过的任何东西,如果在“严格模式”)。其余参数将传递给原始函数。

    [1, 2, 3].forEach.call(["a", "b", "c"], function (item, i, arr) {
        console.log(i + ": " + item);
    });
    // 0: "a"
    // 1: "b"
    // 2: "c"
    

    forEach公司 功能,你正在改变 从空数组到所有 <a> 标签,以及 <a>

    编辑

    下面是一篇文章的链接,建议我们放弃函数式编程的尝试,每次都坚持手动内联循环,因为这种解决方案既有黑客性又难看。

    我要说的是 forEach先生 没有它的对手那么有用, .map(transformer) .filter(predicate) , .reduce(combiner, initialValue) ,当您真正想做的只是修改外部世界(而不是数组)n次,同时可以访问其中任何一个时,它仍然起作用 arr[i] i .

    答案其实很简单,由于疏忽大意,鲍勃叔叔和克罗克福德爵士都会面对这个问题:

    .

    function toArray (arrLike) { // or asArray(), or array(), or *whatever*
      return [].slice.call(arrLike);
    }
    
    var checked = toArray(checkboxes).filter(isChecked);
    checked.forEach(listValues);
    

    现在,如果你问自己是否需要这样做,答案很可能是否定的。。。
    这件事是由。。。如今,每一个具有高阶特征的库。
    如果您使用lodash、下划线甚至jQuery,那么它们都将有一种方法来获取一组元素,并执行n次操作。
    如果你不使用这样的东西,那么无论如何,写你自己的。

    lib.array = (arrLike, start, end) => [].slice.call(arrLike, start, end);
    lib.extend = function (subject) {
      var others = lib.array(arguments, 1);
      return others.reduce(appendKeys, subject);
    };
    

    ES6(ES2015)及更高版本的更新

    不仅是 slice( ) / array( ) /etc-helper方法将使那些希望像使用数组一样使用列表的人的生活变得更容易(因为他们应该这样做),但是对于那些在相对不远的将来有机会在ES6+浏览器中操作的人,或者今天在Babel中有“transpiling”的人来说,你有内置的语言特性,这使得这类事情变得不必要。

    function countArgs (...allArgs) {
      return allArgs.length;
    }
    
    function logArgs (...allArgs) {
      return allArgs.forEach(arg => console.log(arg));
    }
    
    function extend (subject, ...others) { /* return ... */ }
    
    
    var nodeArray = [ ...nodeList1, ...nodeList2 ];
    

    超级干净,非常有用。
    查一下 休息 操作人员;在BabelJS网站试用;如果您的技术堆栈是有序的,使用他们在生产与巴贝尔和一个建设步骤。


    没有理由不使用从非数组到数组的转换。。。别把你的代码搞得一团糟什么都不做 但是 到处贴着同样难看的线。

        2
  •  57
  •   James Allardice    13 年前

    querySelectorAll method NodeList ,它类似于数组,但不完全是数组。因此,它没有 forEach 方法(数组对象通过 Array.prototype ).

    自从 类似于数组,数组方法实际上会处理它,因此 [].forEach.call 您正在调用 Array.prototype.forEach ,就好像你能 yourNodeList.forEach(/*...*/) .

    请注意,空数组文字只是扩展版本的快捷方式,您可能也会经常看到:

    Array.prototype.forEach.call(/*...*/);
    
        3
  •  21
  •   Michael Geary    13 年前

    这是一个很好的例子,说明为了简单明了,应该对代码进行重构。而不是使用 [].forEach.call() Array.prototype.forEach.call()

    function forEach( list, callback ) {
        Array.prototype.forEach.call( list, callback );
    }
    

    现在,您可以调用此函数,而不是更复杂、更晦涩的代码:

    forEach( document.querySelectorAll('a'), function( el ) {
       // whatever with the current node
    });
    
        4
  •  6
  •   Arun P Johny    13 年前

    可以更好地使用

    Array.prototype.forEach.call( document.querySelectorAll('a'), function(el) {
    
    });
    

    是什么 document.querySelectorAll('a') Array 类型。 所以我们称之为 forEach 方法从 Array.prototype 对象的上下文作为

        5
  •  4
  •   vava    6 年前
    [].forEach.call( document.querySelectorAll('a'), function(el) {
       // whatever with the current node
    });
    

    基本上与:

    var arr = document.querySelectorAll('a');
    arr.forEach(function(el) {
       // whatever with the current node
    });
    
        6
  •  2
  •   FrantiÅ¡ek Heča    7 年前

    想更新一下这个老问题:

    使用的原因 [].foreach.call() 在现代浏览器中循环浏览元素的工作基本上已经结束了。我们可以用 document.querySelectorAll("a").foreach() 直接。

    NodeList对象是节点的集合,通常由 属性(如Node.childNodes)和方法(如 document.querySelectorAll()。

    虽然NodeList不是数组, 可以对其进行迭代 . 也可以使用 Array.from()。

    nor Array.from()。这可以通过使用 Array.prototype.forEach()参见本文档的示例。

        7
  •  1
  •   Ted Hopp    13 年前

    空数组有一个属性 forEach forEach公司 所有的功能 Array call 属性,它也是一个函数。调用函数的 this 在被调用函数中。

    您可以找到 功能 here forEach公司 here .

        8
  •  1
  •   iimos    10 年前

    只需添加一行:

    NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;
    

    瞧!

    document.querySelectorAll('a').forEach(function(el) {
      // whatever with the current node
    });
    

    警告: NodeList是一个全局类。如果你在公共图书馆写作,不要使用这个建议。不过,当你在网站或node.js应用程序上工作时,这是一种非常方便的提高自我效能的方法。

        9
  •  1
  •   Alfredo Maria Milano    8 年前

    只是一个我最后总是用的又快又脏的解决方案。我不会碰原型,就像好的做法一样。当然,有很多方法可以让它变得更好,但你知道的。

    const forEach = (array, callback) => {
      if (!array || !array.length || !callback) return
      for (var i = 0; i < array.length; i++) {
        callback(array[i], i);
      }
    }
    
    forEach(document.querySelectorAll('.a-class'), (item, index) => {
      console.log(`Item: ${item}, index: ${index}`);
    });
    
        10
  •  1
  •   ellemenno    6 年前

    这页上有很多好信息(请参阅 answer answer + comment

    Array 数组上的方法,如 NodeList 它本身没有这些方法。

    Function.call() ,并使用数组文字( [] )而不是 Array.prototype

    [].forEach.call(document.querySelectorAll('a'), a => {})
    

    一个更新的模式(后ECMAScript 2015)是使用 Array.from()

    Array.from(document.querySelectorAll('a')).forEach(a => {})
    
        11
  •  0
  •   Xotic750    13 年前

    [] 总是返回一个新数组,相当于 new Array() 但保证返回一个数组,因为 Array 可能被用户覆盖 不能。所以这是一种获得 ,然后如前所述, call

    使用给定的此值和提供的参数调用函数 个别地。 mdn

        12
  •  0
  •   Mikel    8 年前

    Norguard 解释 什么 [].forEach.call() James Allardice 为什么? NodeList

    如果没有,你可以添加一个 Polyfill

    if (window.NodeList && !NodeList.prototype.forEach) {
        NodeList.prototype.forEach = function (callback, thisArg) {
            thisArg = thisArg || window;
            for (var i = 0; i < this.length; i++) {
                callback.call(thisArg, this[i], i, this);
            }
        };
    }