關於如何跳出迴圈?

pro-xiaoy發表於2018-06-25

起因

在視覺化資料的大環境下,前端的頁面驅動基本是基於,每個函式或多或少都會做一些資料上的判斷,這時候就會用到迴圈的跳出。

場景

由於後臺反饋以及前端反饋的資料都是list格式的資料,我先用的是forEach,forEach運用的時候可以更好的便利出item,當然也是習慣性用forEach。但是在forEach中遍歷的時候做的判斷是不支援彈出整個函式,而for迴圈可以。

for迴圈試一下return

  1. 想當然的用return啊,結果:呵呵!
for (let i = 0; i < 3; i++) {
  console.log(110);
  if (i === 1) {
   return
  }
}
複製程式碼

這段程式碼,我想當然的認為:i===1時遇到return跳出迴圈,只會列印兩次110,但是當我在控制檯按下回車時,啪啪啪打臉啊,臉都打腫了,我還不知道為啥!直接報:Illegal return statement

return語句就是用於指定函式返回的值。return語句只能出現在函式體內,出現在程式碼中的其他任何地方都會造成語法錯誤! 地方都會造成語法錯誤!

竟然還有這種限制,為何我以前怎麼沒發覺,仔細看了下以前的程式碼,貌似,我的for都是寫在函式內的,所以沒報錯。。。

當然,為了保險點,又去MDN看了下return,果不其然,MDN上抬頭就是一句:return語句終止函式的執行,並返回一個指定的值給函式呼叫者。

更保險的可以看ECMAScript® 2015 Language Specification return。規範裡面也說了返回語句使函式停止執行,並將值返回給呼叫方。

  1. 既然return不是為for服務的,那麼該怎麼去跳出for迴圈呢? 稍微有基礎的同學們都會想到break和continute。

    在這裡我先給ECMA規範裡的for

    MDN上關於break的說明:break 語句中止當前迴圈,switch語句或label 語句,並把程式控制流轉到緊接著被中止語句後面的語句。break可不僅僅是跳出迴圈這麼簡單哦~

    for (let j = 0; j < 3; j++) {
        console.log(112);
        if (j === 1) {
            break;
        }
    }
    複製程式碼
  2. continue

    結合程式碼看下continue的功能,其實就是break;continue。

        for (let j = 0; j < 3; j++) {
          if (j === 1) {
            continue;
          }
          console.log(j);
        }
    複製程式碼

為什麼不能跳出forEach?

  1. 先用break和continue分別測試一波,看看問題是否成立。
arr.forEach(function(item){
  if (item === 2) {
    break;
  }
  console.log(item);
})
arr.forEach(function(item){
  console.log(110)
  if (item === 2) {
    continue;
  }
  console.log(item);
})
複製程式碼
控制檯均報語法錯誤!!!尤其continue提示沒有包含在一個迭代語句中!!!
去看看MDN上面的forEach,其中明確提到:

沒有辦法中止或者跳出 forEach 迴圈,除了丟擲一個異常。如果你需要這樣,使用forEach()方法是錯誤的,你可以用一個簡單的迴圈作為替代。如果您正在測試一個陣列裡的元素是否符合某條件,且需要返回一個布林值,那麼可使用Array.everyArray.some。如果可用,新方法 find() 或者findIndex() 也可被用於真值測試的提早終止。

同時,去看看規範裡的forEach。貌似沒有說為什麼。那麼怎麼辦呢?

回顧continue報錯提示,需要被包含在迭代語句內,難道forEach不是迭代語句嗎?它作用不就是遍歷 嗎?抱著這些問題,我在規範的目錄裡走馬觀花的檢視,突然發現這個Iteration Statements,這個目錄名不就是continue要求的迭代語句嘛。

我點了下去,大致看了下,果然沒有forEach,而且mapfilter等都沒有。。。

我有嘗試去看v8關於forEach的原始碼實現,可惜並沒有找到。。。

不過這裡可以提供一個仿map方法的_map,本質上是一樣的,只是側重點不同,有些實現不同。我們平常這樣使用:arr.forEach(function(){}),我們都是在function(){}中去做我們需要的操作,但是,forEach本質上就是一個函式,而我們寫的函式其實是傳遞給它呼叫的回撥函式!!!

所以,當我在回撥函式內寫了return,即使符合條件也只是跳出回撥函式而已,並沒有跳出呼叫它的forEach!

demo
function a(i) {
  console.log(i);
  if(i === 1) {
    return
  }
}
function b(arr) {
  for(var i = 0; i < arr.length; i++) {
    a(i)
  }
}
var arr = [1,2,3,4,5]
b(arr)
複製程式碼

總結下

由這一個小問題挖掘出這麼多小知識也是不錯的,有利於夯實js基礎。以後遇到類似的業務場景時,可以更好利用出來。

相關文章