版本

no-implicit-globals

禁止在全域範圍中宣告變數

最佳實務是避免使用打算作為腳本本地變數的變數「污染」全域範圍。

從一個腳本建立的全域變數可能會與從另一個腳本建立的全域變數產生名稱衝突,這通常會導致執行階段錯誤或非預期的行為。

此規則禁止以下行為

  • 在全域範圍中建立一個或多個變數的宣告。
  • 全域變數洩漏。
  • 重新宣告唯讀全域變數以及對唯讀全域變數進行賦值。

當需要時,有一種明確的方式可以建立全域變數,即賦值給全域物件的屬性。

此規則主要適用於瀏覽器腳本。ES 模組和 CommonJS 模組中的頂層宣告會建立模組範圍的變數。ES 模組也具有隱式 `strict` 模式,可防止全域變數洩漏。

預設情況下,此規則不會檢查 `const`、`let` 和 `class` 宣告。

此規則具有一個物件選項,其中包含一個選項

  • 如果您希望此規則也檢查 `const`、`let` 和 `class` 宣告,請將 `"lexicalBindings"` 設定為 `true`。

規則詳細資訊

`var` 和 `function` 宣告

在使用瀏覽器腳本時,開發人員經常忘記頂層範圍中的變數和函式宣告會變成 `window` 物件上的全域變數。這與具有自己範圍的模組相反。如果這是本意,則應將全域變數明確指派給 `window` 或 `self`。否則,打算作為腳本本地變數的變數應包裝在 IIFE 中。

此規則禁止在頂層腳本範圍中使用 `var` 和 `function` 宣告。這不適用於 ES 和 CommonJS 模組,因為它們具有模組範圍。

此規則的**不正確**程式碼範例

在遊樂場中開啟
/*eslint no-implicit-globals: "error"*/

var foo = 1;

function bar() {}

此規則的**正確**程式碼範例

在遊樂場中開啟
/*eslint no-implicit-globals: "error"*/

// explicitly set on window
window.foo = 1;
window.bar = function() {};

// intended to be scope to this file
(function() {
  var foo = 1;

  function bar() {}
})();

在 ESLint 設定中使用 ` "parserOptions": { "sourceType": "module" }` 時,此規則的**正確**程式碼範例

在遊樂場中開啟
/*eslint no-implicit-globals: "error"*/

// foo and bar are local to module
var foo = 1;
function bar() {}

全域變數洩漏

當程式碼不在 `strict` 模式下時,對未宣告變數進行賦值會建立一個新的全域變數。即使程式碼在函式中也會發生這種情況。

這不適用於 ES 模組,因為模組程式碼隱式處於 `strict` 模式下。

此規則的**不正確**程式碼範例

在遊樂場中開啟
/*eslint no-implicit-globals: "error"*/

foo = 1;

Bar.prototype.baz = function () {
    a = 1; // Intended to be this.a = 1;
};

唯讀全域變數

此規則也禁止重新宣告唯讀全域變數以及對唯讀全域變數進行賦值。

唯讀全域變數可以是內建的 ES 全域變數(例如 `Array`)、特定於環境的全域變數(例如瀏覽器環境中的 `window`)或在設定檔或 `/*global */` 註解中定義為 `readonly` 的全域變數。

此規則的**不正確**程式碼範例

在遊樂場中開啟
/*eslint no-implicit-globals: "error"*/

/*global foo:readonly*/

foo = 1;

Array = [];
var Object;

`const`、`let` 和 `class` 宣告

詞彙宣告 `const` 和 `let` 以及 `class` 宣告會建立區塊範圍的變數。

但是,當在瀏覽器腳本的頂層宣告時,這些變數不是「腳本範圍」。它們實際上是在全域範圍中建立的,可能會與來自其他腳本的 `var`、`const` 和 `let` 變數以及 `function` 和 `class` 宣告產生名稱衝突。這不適用於 ES 和 CommonJS 模組。

如果變數打算作為腳本的本地變數,請使用區塊或立即調用函式運算式 (IIFE) 包裝程式碼。

將 `lexicalBindings` 選項設定為 `false`(預設值)時,此規則的**正確**程式碼範例

在遊樂場中開啟
/*eslint no-implicit-globals: ["error", {"lexicalBindings": false}]*/

const foo = 1;

let baz;

class Bar {}

將 `lexicalBindings` 選項設定為 `true` 時,此規則的**不正確**程式碼範例

在遊樂場中開啟
/*eslint no-implicit-globals: ["error", {"lexicalBindings": true}]*/

const foo = 1;

let baz;

class Bar {}

將 `lexicalBindings` 選項設定為 `true` 時,此規則的**正確**程式碼範例

在遊樂場中開啟
/*eslint no-implicit-globals: ["error", {"lexicalBindings": true}]*/

{
    const foo = 1;
    let baz;
    class Bar {}
}

(function() {
    const foo = 1;
    let baz;
    class Bar {}
}());

如果您打算建立全域 `const` 或 `let` 變數或全域 `class` 宣告,以便從其他腳本中使用,請注意,與傳統方法相比,有一些差異,傳統方法是 `var` 宣告和賦值給全域 `window` 物件的屬性

  • 無法有條件地建立詞彙宣告的變數。腳本無法檢查變數是否存在,然後建立一個新變數。`var` 變數也始終會建立,但重新宣告不會導致執行階段例外。
  • 詞彙宣告的變數不會在全域物件上建立屬性,這是使用腳本可能期望的。
  • 詞彙宣告的變數會遮蔽全域物件的屬性,如果使用腳本同時使用變數和屬性,則可能會產生錯誤。
  • 如果初始化擲回例外,詞彙宣告的變數可能會產生永久的暫時性死區 (TDZ)。即使 `typeof` 檢查也無法避免 TDZ 參考例外。

將 `lexicalBindings` 選項設定為 `true` 時,此規則的**不正確**程式碼範例

在遊樂場中開啟
/*eslint no-implicit-globals: ["error", {"lexicalBindings": true}]*/

const MyGlobalFunction = (function() {
    const a = 1;
    let b = 2;
    return function() {
        return a + b;
    }
}());

將 `lexicalBindings` 選項設定為 `true` 時,此規則的**正確**程式碼範例

在遊樂場中開啟
/*eslint no-implicit-globals: ["error", {"lexicalBindings": true}]*/

window.MyGlobalFunction = (function() {
    const a = 1;
    let b = 2;
    return function() {
        return a + b;
    }
}());

exported

您可以使用 `/* exported variableName */` 區塊註解,就像在 `no-unused-vars` 中一樣。請參閱 `no-unused-vars` 的 exported 區段以瞭解詳細資訊。

`/* exported variableName */` 操作的**正確**程式碼範例

在遊樂場中開啟
/* eslint no-implicit-globals: error */
/* exported global_var */

var global_var = 42;

何時不應使用它

在瀏覽器腳本的情況下,如果您希望能夠明確地宣告全域範圍中的變數和函式,並且您的程式碼處於嚴格模式,或者您不希望此規則警告您有關未宣告的變數,並且您也不希望此規則警告您有關唯讀全域變數,則可以停用此規則。

在 CommonJS 模組的情況下,如果您的程式碼處於嚴格模式,或者您不希望此規則警告您有關未宣告的變數,並且您也不希望此規則警告您有關唯讀全域變數,則可以停用此規則。

在 ES 模組的情況下,如果您不希望此規則警告您有關唯讀全域變數,則可以停用此規則。

版本

此規則是在 ESLint v2.0.0-alpha-1 中引入的。

進一步閱讀

資源

變更語言