es6 if包裹的變數算塊內嗎

2022-11-21 18:05:00

es6 if包裹的變數算塊內。es6中新增了塊級作用域,被「{ }」包裹住的程式碼就是塊級作用域;函數中的「{}」、if語句、for迴圈內的程式碼都屬於塊級作用域,是算在塊內的。在es6中,允許塊級作用域任意巢狀,外層作用域無法讀取內層作用域的變數;內層作用域可以定義外層作用域的同名變數。

前端(vue)入門到精通課程:進入學習
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:

本教學操作環境:windows7系統、ECMAScript 6版、Dell G3電腦。

什麼是塊級作用域

ES6 中新增了塊級作用域。塊作用域由 { } 包裹,if 語句和 for 語句裡面的 { } 也屬於塊作用域。

函數中的{},if語句,for迴圈,也是屬於塊級作用域,let與const定義的變數只能在作用域有效。

為什麼需要塊級作用域

第一種場景:內部變數會覆蓋外部變數

var time = new Date()
function fx () {
    console.log(time) // undefined
    if (false) {
        var time = 'hello'
    }
}
fx()
登入後複製
{
    var a = 1
    console.log(a) // 1
}
console.log(a) // 1
// 通過var定義的變數可以跨塊作用域存取到。
登入後複製

第二種場景:用來計數的迴圈變數洩漏為全域性變數

for 迴圈中的用 var 定義的變數在外部作用域可以存取

for (var i = 0; i < 3; i++) {

}

for (let j = 0; j < 3; j++) {

}
// 3
console.log(i);
// Uncaught ReferenceError: j is not defined
console.log(j);
登入後複製

if 語句中 var 定義的變數在外部作用域可以存取

if(true)if (false) 的區別

  • if(true) 中的賦值語句會被執行,所以 a 列印出來是 3
  • if(false) 中的賦值語句不會被執行,但宣告的變數 var b 會由於變數提升,提升到作用域的頂層,所以列印出來是 undefined
if (true) {
	var a = 3
}

if (false) {
	var b = 3
}
// 3
console.log(a);
// undefined
console.log(b);

if (true) {
	let c = 3
}
// Uncaught ReferenceError: c is not defined
console.log(c);
登入後複製

塊級作用域(ES6 提供 let & const 變數實現塊級作用域)

function fxFn () { // 這是一個塊級作用域
    let fx = 'fx is a great girl'
    if (true) { // 這是一個塊級作用域
        let fx = 'fx is 18 years old'
    }
    console.log(fx) // fx is a great girl
}
fxFn()
 
// 塊級作用域之間相互不影響
登入後複製

ES6 允許塊級作用域的任意巢狀。

{{{{
  {
    let fnn = 'Hello'
  }
  console.log(fnn); // 報錯
}}}};
登入後複製

上面程式碼使用了一個五層的塊級作用域,每一層都是一個單獨的作用域。第四層作用域無法讀取第五層作用域的內部變數。

  • 內層作用域可以定義外層作用域的同名變數。
{{{{
  let fnn = 'Hello';
  {
    let fnn = 'Hello'
  }
}}}};
登入後複製

塊級作用域的出現,實際上使得獲得廣泛應用的匿名立即執行函數表示式(匿名 IIFE)不再必要了。

// IIFE 寫法
(function () {
  var tmp = '...';
  // ...
}());
 
// 塊級作用域寫法
{
  let tmp = '...';
  // ...
}
登入後複製

塊級作用域與函數宣告

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 環境
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 規定,瀏覽器的實現可以不遵守上面的規定,有自己的行為方式

  • 允許在塊級作用域內宣告函數。
  • 函數宣告類似於 var,即會提升到全域性作用域或函數作用域的頭部。
  • 同時,函數宣告還會提升到所在的塊級作用域的頭部。

注意,上面三條規則只對 ES6 的瀏覽器實現有效,其他環境的實現不用遵守,還是將塊級作用域的函數宣告當作 let 處理。

根據這三條規則,瀏覽器的 ES6 環境中,塊級作用域內宣告的函數,行為類似於 var 宣告的變數。上面的例子實際執行的程式碼如下。

// 瀏覽器的 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 的塊級作用域必須有大括號

如果沒有大括號,JavaScript 引擎就認為不存在塊級作用域。

// 第一種寫法,報錯
if (true) let x = 1;
 
// 第二種寫法,不報錯
if (true) {
  let x = 1;
}
登入後複製

上面程式碼中,第一種寫法沒有大括號,所以不存在塊級作用域,而let只能出現在當前作用域的頂層,所以報錯。第二種寫法有大括號,所以塊級作用域成立。

函數宣告也是如此,嚴格模式下,函數只能宣告在當前作用域的頂層。

// 不報錯
'use strict';
if (true) {
  function f() {}
}
 
// 報錯
'use strict';
if (true)
  function f() {}
登入後複製

【推薦學習:】

以上就是es6 if包裹的變數算塊內嗎的詳細內容,更多請關注TW511.COM其它相關文章!