知道臨時死區你才能更好的使用 JS 變量

做者:Dmitri Pavlutin
譯者:前端小智
來源:dmitripavlutin

點贊再看,養成習慣

本文 GitHub https://github.com/qq44924588... 上已經收錄,更多往期高贊文章的分類,也整理了不少個人文檔,和教程資料。歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。javascript


首先,來個一個簡單的問題。下列哪段代碼會產生錯誤:前端

第一個建立實例,而後定義使用的類:java

new Car('red'); // 是否會報錯?

class Car {
  constructor(color) {
    this.color = color;
  }
}

或者先於函數定義以前調用函數:git

greet('World'); // 是否會報錯?

function greet(who) {
  return `Hello, ${who}!`;
}

正確的答案是:第一個代碼片斷會報 ReferenceError: Cannot access 'Car' before initialization 錯誤。第二個代碼正常運行。github

若是你的答案與上述不一樣,或者你在不知道這背後的原理是什麼而進行了猜想,那麼你須要掌握臨時死區(TDZ)的知識。面試

TDZ 管理 letconstclass 語法的可用性。變量在 JS 中的工做方式很是重要。服務器

1.什麼是臨時死區

我們先從一個簡單的 const 變量聲明開始。 首先聲明並初始化變量,而後訪問它,一切正常運行:微信

const white = '#FFFFFF';

white; // => '#FFFFFF'

那若是在 聲明以前訪問 white 變量,會怎麼樣》函數

white; // throws `ReferenceError`

const white = '#FFFFFF';

white;

const white = '#FFFFFF' 語句以前的代碼行中,變量 white 位於臨時死區工具

TDZ 中訪問 white 後,JS拋出ReferenceError: Cannot access 'white' before initialization

clipboard.png

臨時死區語義禁止在變量聲明以前訪問它。它增強了順序:在聲明以前不要使用任何東西。

2.受 TDZ 影響的聲明

來看看受 TDZ 影響的聲明。

2.1 const變量

如前所述,const 變量位於聲明和初始化行以前的 TDZ 中:

// 沒法工做
pi; // throws `ReferenceError`

const pi = 3.14;

我們必須在聲明以後使用 const 變量:

const pi = 3.14;

// Works!
pi; // => 3.14

2.2 let 變量

在聲明行以前,let 聲明語句也會受到 TDZ 的影響:

// 沒法工做
count; // throws `ReferenceError`

let count;

count = 10;

一樣,僅在聲明以後使用 let 變量:

let count;

// Works!
count; // => undefined

count = 10;

// Works!
count; // => 10

2.3 class 的聲明

正如在介紹中看到的,在定義 class 以前不能使用它:

// 沒法工做
const myNissan = new Car('red'); // throws `ReferenceError`

class Car {
  constructor(color) {
    this.color = color;
  }
}

2.4 構造函數內部的 super()

若是在構造函數中調用 super()以前擴展父類,則此綁定位於 TDZ 中。

class MuscleCar extends Car {
  constructor(color, power) {
    this.power = power;
    super(color);
  }
}

// Does not work!
const myCar = new MuscleCar('blue', '300HP'); // `ReferenceError`

在構造 constructor() 中,在調用super()以前不能使用 this

TDZ 建議調用父構造函數來初始化實例。這樣作以後,實例就準備好了,就能夠在子構造函數中進行調整。

class MuscleCar extends Car {
  constructor(color, power) {
    super(color);
    this.power = power;
  }
}

// Works!
const myCar = new MuscleCar('blue', '300HP');
myCar.power; // => '300HP'

2.5 默認函數參數

默認參數存在於一箇中間做用域中,與全局做用域和函數做用域分離。默認參數也遵循 TDZ 限制。

const a = 2;
function square(a = a) {
  return a * a;
}
// Does not work!
square(); // throws `ReferenceError`

在聲明表達式 a = a以前,在表達式的右側使用參數 a,這將生成關於 a 的引用錯誤。

確保在聲明和初始化以後使用默認參數。 我們可使用一個特殊的變量 init,該變量在使用前已初始化:

const init = 2;
function square(a = init) {
  return a * a;
}
// Works!
square(); // => 4

3.var, function, import 語句

與上述陳述相反,varfunction 定義不受 TDZ 的影響。它們被提高到當前的做用域頂部。

若是在聲明以前訪問 var 變量,則只會獲得一個 undefined 的變量

// 正常運行, 但不要這樣作!
value; // => undefined

var value;

可是,能夠根據函數的定義位置來使用它:

// 正常工做
greet('World'); // => 'Hello, World!'

function greet(who) {
  return `Hello, ${who}!`;
}

// 正常工做
greet('Earth'); // => 'Hello, Earth!'

一般,我們通常對函數的實現不太感興趣,而只是想調用它。 所以,有時在定義函數以前先調用該函數是有意義的。

有趣的是,import 模塊也被提高了。

// 正常工做
myFunction();

import { myFunction } from './myModule';

固然,建議將 import 寫在文件開頭,以便讀寫方法。

你們都說簡歷沒項目寫,我就幫你們找了一個項目,還附贈【搭建教程】

我和阿里雲合做服務器,折扣價比較便宜:89/年,223/3年,比學生9.9每個月還便宜,買了搭建個項目,熟悉技術棧比較香(老用戶用家人帳號買就行了,我用我媽的)推薦買三年的划算點,點擊本條就能夠查看。

4. TDZ 中的 typeof 行爲

typeof 操做符用於肯定是否在當前做用域內定義了變量。

例如,未定義變量 notDefined。對該變量應用 typeof 操做符不會引起錯誤:

typeof notDefined; // => 'undefined'

由於變量沒有定義,因此 typeof notDefined 的值爲 undefined

可是 typeof 操做符在與臨時死區中的變量一塊兒使用時具備不一樣的行爲。在本例中,JS 拋出一個錯誤:

typeof variable; // throws `ReferenceError`

let variable;

此引用錯誤背後的緣由是您能夠靜態地(僅經過查看代碼)肯定已經定義了該變量。

5. TDZ 在當前做用域內採起行動

臨時死區在聲明語句所在的做用域內影響變量。

clipboard.png

來看看例子:

function doSomething(someVal) {
  // 函數做用域
  typeof variable; // => undefined
  if (someVal) {
    // 內部塊使用域
    typeof variable; // throws `ReferenceError`
    let variable;
  }
}
doSomething(true);

有 2 個做用域:

  • 函數做用域
  • 定義 let 變量的內部塊做用域

在函數做用域中,typeof variable 的計算結果爲 undefined。在這裏,let 變量語句的 TDZ 沒有做用。

在內部做用域中,typeof variable 語句在聲明以前使用一個變量,拋出一個錯誤。ReferenceError:在初始化以前不能訪問‘variable’,TDZ 只存在於這個內部做用域內。

6.總結

TDZ 是影響 constletclass 語句可用性的重要概念。它不容許在聲明以前使用變量。

相反,能夠在聲明以前使用 var 變量時,var 變量會繼承較舊的行爲,應該避免這樣作。

在我看來,TDZ是語言規範中良好的編碼實踐之一。


代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

原文:https://dmitripavlutin.com/ja...


交流

文章每週持續更新,能夠微信搜索「 大遷世界 」第一時間閱讀和催更(比博客早一到兩篇喲),本文 GitHub https://github.com/qq449245884/xiaozhi 已經收錄,整理了不少個人文檔,歡迎Star和完善,你們面試能夠參照考點複習,另外關注公衆號,後臺回覆福利,便可看到福利,你懂的。

相關文章
相關標籤/搜索