【ES6】塊級作用域與函式宣告
阿新 • • 發佈:2018-12-22
塊級作用域與函式宣告
ES5 規定,函式只能在頂層作用域和函式作用域之中宣告,不能在塊級作用域宣告。
// 情況一
if (true) {
function f() {}
}
// 情況二
try {
function f() {}
} catch(e) {
// ...
}
上面兩種函式宣告,根據 ES5 的規定都是非法的。
但是,瀏覽器沒有遵守這個規定,為了相容以前的舊程式碼,還是支援在塊級作用域之中宣告函式,因此上面兩種情況實際都能執行,不會報錯。
ES6 引入了塊級作用域,明確允許在塊級作用域之中宣告函式。ES6 規定,塊級作用域之中,函式宣告語句的行為類似於let,在塊級作用域之外不可引用。
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// 重複宣告一次函式f
function f() { console.log('I am inside!'); }
}
f();
}());
上面程式碼在 ES5 中執行,會得到“I am inside!”,因為在 if 內宣告的函式 f 會被提升到函式頭部,實際執行的程式碼如下。
// ES5 環境
function f() { console.log('I am outside!'); }
(function () {
function f() { console.log('I am inside!'); }
if (false) {
}
f();
}());
ES6 就完全不一樣了,理論上會得到“I am outside!”。因為塊級作用域內宣告的函式類似於let,對作用域之外沒有影響。但是,實際上在 ES6 瀏覽器中執行上面的程式碼,是會報錯的,這是為什麼呢?
原來,如果改變了塊級作用域內宣告的函式的處理規則,顯然會對老程式碼產生很大影響。為了減輕因此產生的不相容問題,ES6 在附錄 B裡面規定,瀏覽器的實現可以不遵守上面的規定,有自己的行為方式。
- 允許在塊級作用域內宣告函式。
- 函式宣告類似於var,即會提升到全域性作用域或函式作用域的頭部。
- 同時,函式宣告還會提升到所在的塊級作用域的頭部。
根據這三條規則,在瀏覽器的 ES6 環境中,塊級作用域內宣告的函式,行為類似於var宣告的變數。
// 瀏覽器的 ES6 環境
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// 重複宣告一次函式f
function f() { console.log('I am inside!'); }
}
f();
}());
// Uncaught TypeError: f is not a function
上面的程式碼在符合 ES6 的瀏覽器中,都會報錯,因為實際執行的是下面的程式碼。
// 瀏覽器的 ES6 環境
function f() { console.log('I am outside!'); }
(function () {
var f = undefined;
if (false) {
function f() { console.log('I am inside!'); }
}
f();
}());
// Uncaught TypeError: f is not a function
考慮到環境導致的行為差異太大,應該避免在塊級作用域內宣告函式。如果確實需要,也應該寫成函式表示式,而不是函式宣告語句。
// 函式宣告語句
{
let a = 'secret';
function f() {
return a;
}
}
// 函式表示式
{
let a = 'secret';
let f = function () {
return a;
};
}
另外,還有一個需要注意的地方。ES6 的塊級作用域允許宣告函式的規則,只在使用大括號的情況下成立,如果沒有使用大括號,就會報錯。
// 不報錯
'use strict';
if (true) {
function f() {}
}
// 報錯
'use strict';
if (true)
function f() {}