如何使用函数调用代替循环跳转?

时间:2017-03-06 01:45:27

标签: javascript loops

我目前正在研究如何在MDN的javascript中使用“标记”循环并遇到以下短语。

enter image description here

我理解标记的循环有时用于将代码执行转移到几层的外循环。但我不明白作者的意思是“通常可以使用函数调用而不是循环跳转”。有人可以请我提供一个例子吗?

3 个答案:

答案 0 :(得分:2)

以下是一个示例,它搜索2D数组array,查找元素n,并在找到时打印坐标:

function searchAndLogCoords(array, n) {
    // The "searching" portion of the function
    outterLoop:
    for (i = 0; i < array.length; i++) {
        row = array[i]

        for (j = 0; j < row.length; j++) {
            // Break out of the "searching" portion of the function,
            // and continue on to the "logging" portion
            if (row[j] == n) break outterLoop
        }
    }

    // The "logging" portion of the function
    console.log("x: " + i + ", y: " + j)
}

var array = [
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 1, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0]
];

searchAndLogCoords(array, 1)

这里的代码相同,最好通过提取&#34;搜索&#34;部分进入自己的功能:

searchAndLogCoords(array, 1)
function searchAndLogCoords(array, n) {
    for (i = 0; i < array.length; i++) {
        row = array[i]

        for (j = 0; j < row.length; j++) {
            if (row[j] == n) return {x: i, y: j}
        }
    }
}

function getCoords(array, n) {
    var coords = searchAndLogCoords(array, n)
    console.log("x: " + coords.x + ", y: " + coords.y)
}

var array = [
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 1, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0]
];

searchAndLogCoords(array, 1)

您可以在线试用here

答案 1 :(得分:1)

我不是这篇文章的作者,但我很确定这就是他的意思:

鉴于此示例(来自该文章):

loop1:
for (i = 0; i < 3; i++) {      //The first for statement is labeled "loop1"
   loop2:
   for (j = 0; j < 3; j++) {   //The second for statement is labeled "loop2"
      if (i === 1 && j === 1) {
         continue loop1;
      }
      console.log('i = ' + i + ', j = ' + j);
   }
}

您可以将其转移到:

for (i = 0; i < 3; i++){
    (function(){
        for (j = 0; j < 3; j++){
           if (i === 1 && j === 1)
               return;
           console.log('i = ' + i + ', j = ' + j);
        }
    }());
}

其中不包含任何标记的循环,但通过从内部函数返回来打破内循环。

当然,你可以在其他地方声明这个内部函数,然后调用它,但这样,你保持外部函数的当前范围。

答案 2 :(得分:1)

我可以想到需要标签的两种常见情况。第一个是当你需要退出嵌套循环时。

(gdb) run
Starting program: /home/user/Desktop/net-tools-1.60/arp 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) where
#0  0x0000000000000000 in ?? ()
#1  0x00007ffff6c83fa9 in __pthread_initialize_minimal_internal () at nptl-init.c:471
#2  0x00007ffff6c83589 in _init () at ../sysdeps/x86_64/crti.S:72
#3  0x00007ffff70a4670 in ?? () from /lib/x86_64-linux-gnu/libnss_myhostname.so.2
#4  0x00000000004acd5a in call_init.part ()
#5  0x00000000004acf15 in _dl_init ()
#6  0x00000000004999a5 in dl_open_worker ()
#7  0x0000000000497164 in _dl_catch_error ()
#8  0x0000000000499309 in _dl_open ()
#9  0x00000000004563d2 in do_dlopen ()
#10 0x0000000000497164 in _dl_catch_error ()
#11 0x00000000004565be in __libc_dlopen_mode ()
#12 0x0000000000451e6d in __nss_next2 ()
#13 0x000000000044dbac in gethostbyaddr_r ()
#14 0x000000000044d9be in gethostbyaddr ()
#15 0x00000000004031f2 in INET_rresolve (name=name@entry=0x6e68e0 <buff> "", sin=0x7fffffffd440, 
    numeric=<optimized out>, netmask=netmask@entry=4294967040, len=128) at inet.c:200
#16 0x0000000000403354 in INET_sprint (sap=<optimized out>, numeric=<optimized out>) at inet.c:246
#17 0x0000000000401877 in arp_show (name=0x0) at arp.c:581
#18 0x0000000000400b53 in main (argc=1, argv=0x7fffffffe008) at arp.c:768
(gdb)

可以采用以下代码代替:

outerloop: while (conditionA) {
  innerloop: while (conditionB) {
    doSomething();
    if (exitCondition) break outerloop;
  }
}

这利用了自执行函数的return语句来同时中断两个循环。

另一种情况是你希望在没有完成当前循环的情况下继续外循环。

(function () {
  while (conditionA) {
    while (conditionB) {
      doSomething();
      if (exitCondition) return;
    }
  }
})();

我设法替换了这个:

outerloop: while (conditionA) {
  innerloop: while (conditionB) {
    doSomething();
    if (continueCondition) {
      continue outerloop;
    }
  }
  doSomething(); // we don't want this to run if continueCondition is true
}

这次我决定使用命名函数来提高可读性。但说实话,我会找到一种方法来重写循环,如果可以的话,不需要像那样继续。复杂的循环很难维护。

要记住的重要一点是,不仅有一种方法可以做。