看一個以下的例子。在函數 foo 中,使用了一組 try 語句。在 try 中有 return 語句,finally 中的內容還會執行嗎?chrome
function foo(){ try{ return 0; } catch(err) { } finally { console.log("a") } }
獲得的結果是:a 0。函數
根據結果能夠看出finally執行了,return語句也生效了。工具
雖然 return 執行了,可是函數並無當即返回,又執行了 finally 裏面的內容,這樣的行爲違背了不少人的直覺。spa
咱們改一下上面的例子,在finally也加入return語句,以下:調試
function foo(){ try{ return 0; } catch(err) { } finally { return 1; } }
獲得的結果是:1code
經過實際執行,咱們看到,finally 中的 return 「覆蓋」了 try 中的 return。在一個函數中執行了兩次 return,這已經超出了不少人的常識,也是其它語言中不會出現的一種行爲。orm
面對如此怪異的行爲,咱們固然能夠把它做爲一個孤立的知識去記憶,可是實際上,這背後有一套機制在運做。blog
這一機制的基礎正是 JavaScript 語句執行的完成狀態,咱們用一個標準類型來表示:Completion Record(Completion Record 用於描述異常、跳出等語句執行過程)。ip
Completion Record 表示一個語句執行完以後的結果,它有三個字段:get
JavaScript 正是依靠語句的 Completion Record 類型,方纔能夠在語句的複雜嵌套結構中,實現各類控制。接下來咱們要來了解一下 JavaScript 使用 Completion Record 類型,控制語句執行的過程。
語句的分類以下:
普通語句執行後,會獲得 [[type]] 爲 normal 的 Completion Record,JavaScript 引擎遇到這樣的 Completion Record,會繼續執行下一條語句。
這些語句中,只有表達式語句會產生 [[value]],固然,從引擎控制的角度,這個 value 並無什麼用處。
若是你常常使用 chrome 自帶的調試工具,能夠知道,輸入一個表達式,在控制檯能夠獲得結果,可是在前面加上 var,就變成了 undefined。
Chrome 控制檯顯示的正是語句的 Completion Record 的 [[value]]。
如今解釋下在finally也加入return語句後,爲何獲得的結果爲1?
由於 finally 中的內容必須保證執行,因此 try/catch 執行完畢,即便獲得的結果是非 normal 型的完成記錄,也必需要執行 finally。
而當 finally 執行也獲得了非 normal 記錄,則會使 finally 中的記錄做爲整個 try 結構的結果。
帶標籤的語句的做用:與完成記錄類型中的 target 相配合,用於跳出多層循環。
實際上,任何 JavaScript 語句是能夠加標籤的,在語句前加冒號便可:
firstStatement: var i = 1;
跳出循環的例子:
top: for (var i = 0; i < 3; i++){ for (var j = 0; j < 3; j++){ if (i === 1 && j === 1) break top; console.log('i=' + i + ', j=' + j); } } // i=0, j=0 // i=0, j=1 // i=0, j=2 // i=1, j=0