令人难以置信的循环功能

时间:2011-03-17 05:33:12

标签: javascript

如果有人可以帮我理解这个,我会留下深刻的印象。这是来自John Resig's advanced JavaScript的#28。

这是一个循环函数,如果你看一下教程,它似乎会运行3次,产生下面的6 Pass。

请您用简明的语言尽可能详细地解释本计划中发生的事情,并在此过程中解释:

  1. fn.call(array, array[i], i)为什么函数有这3个参数以及它们如何工作。该函数首先处理数组,然后是数组[i],然后是i?所有这一切都在发生什么?

  2. 此外,在函数中,我理解i++每次通过array.length时都会上升,但是什么触发num++来增加它的值,以及以什么方式是value == num++

  3. function(value, i)中,value是什么?值是否交替0,1,2的循环数组?如果是这样,那些循环数组如何作为function(value, i)

  4. 中的参数传递
  5. this instanceof Array这是在尝试展示什么?怎么样?

  6. 代码:

    function loop(array, fn){ 
      for ( var i = 0; i < array.length; i++ ) 
        fn.call( array, array[i], i ); 
    } 
    var num = 0; 
    loop([0, 1, 2], function(value, i){ 
      assert(value == num++, "Make sure the contents are as we expect it."); 
      assert(this instanceof Array, "The context should be the full array."); 
    });
    
    通过确保内容符合我们的预期。
    通过上下文应该是完整的数组。
    通过确保内容符合我们的预期。
    通过上下文应该是完整的数组。
    通过确保内容符合我们的预期。
    通过上下文应该是完整的数组。

4 个答案:

答案 0 :(得分:3)

function是一个匿名函数,即没有名称的函数。 loop的完整第二个参数是

function(value, i) {
  assert(value == num++, "Make sure the contents are as we expect it.");
  assert(this instanceOf Array, "The context should be the full array.");
}

这是一个完整的匿名函数,它接受三个参数:this(它是一个方法的对象),当前值和循环计数器。

loop遍历数组,并使用fn.call来调用匿名函数,并传递三个参数;这里,数组对象必须是显式的,因为call无法知道调用它的函数引用应该调用哪个上下文(即调用中的this)。< / p>

loop调用的匿名函数将数组作为this接收。第二个ASSERT验证了这一点。它还期望数组的值为[0, 1, 2]并通过在每次调用时递增num并将其与传递的数组元素进行比较来验证这一点。

所以,遵循执行链:

  1. num被声明并初始化为0.
  2. loop([0, 1, 2], function ...)被调用。
  3. loop调用fn,匿名函数,数组(作为this),它的第一个元素,i表示元素偏移量。 (i从未实际使用过。)
  4. 匿名函数ASSERT通过与num进行比较并随后递增num来传递预期的第一个元素0。
  5. 匿名函数ASSERT,其thisArray
  6. loop调用{3}中的fn,但使用第二个数组元素。
  7. 匿名函数再次执行ASSERT s,这次将传递的第二个数组元素(预期为1)与num进行比较(由于步骤4中的后增量, ,是1)。
  8. loop像以前一样使用第三个数组元素调用fn
  9. 匿名函数再次执行ASSERT次,这次将预期的数组元素2与值{2}的num进行比较。

答案 1 :(得分:2)

fn是指向调用循环时创建的匿名函数的函数指针。

a)有三个参数,因为第一个是对你要作用的对象的引用,即数组,第二个参数只是数组迭代中的当前值,第三个值是该元素在该数组中的位置。

b)当你调用num ++时,它会增加num的值。后增量返回值(也称为赋值),然后递增num。

c)value是fn.call传递的第二个参数。

d) this 是指您在fn.call()调用中传递给第一个parmater的数组。

答案 2 :(得分:2)

我认为理解正在发生的事情的一种更简单的方法是删除call的用法,而是直接调用该方法 - 旧方式。

function loop(array, fn) {
    for(var i = 0; i < array.length; i++)
        fn(array[i], i);
}

var num = 0;
loop([0, 1, 2], function(value, i) {
    assert(value == num, "Make sure the contents are as we expect it.");
    assert(this instanceof Array, "The context should be the full array.");
    num++;
});

如果您在源url上运行此代码,则每次都会看到this instanceof Array测试失败,因为this不再指向Array实例。

要使this指向Array的实例,我们需要使用callapply调用该方法。

fn.call(array, array[i], i);

第一个参数是this将指向的内容。此处的所有其他参数都作为参数传递给被调用的函数。请注意,我们可以在这里作弊通过测试。我们可以传递任何 Array对象来进行第二次测试,而不是传递 array我们正在循环的对象。

fn.call([], array[i], i);
fn.call([1,2,3,4,5], array[i], i);

答案 3 :(得分:1)

我实际上并不知道javascript,但我相信我理解发生了什么......

前四行定义了一个名为loop的函数。循环包含两个变量,一个数组和一个函数。我认为第二个参数是函数的唯一原因是因为编码器调用了可能调用该函数的变量。该函数循环遍历数组的元素,并通过调用方法以某种方式将它们传递给函数。你应该看看这部分。

定义之后,num被定义为从零开始。

然后是有趣的部分。使用参数[0,1,2]和在现场创建的匿名函数调用函数循环。 function(value,i)和之后的所有内容都是这个匿名函数的定义。它没有名称,但只为此函数调用定义。该函数检查以确保该值等于num并在其后增加num,然后检查以确保该变量是一个数组。