版本

no-implicit-globals

禁止在全局作用域中声明

最佳实践是避免用旨在成为脚本本地变量的变量“污染”全局作用域。

从一个脚本创建的全局变量可能会与从另一个脚本创建的全局变量产生名称冲突,这通常会导致运行时错误或意外行为。

此规则禁止以下情况

  • 在全局作用域中创建一个或多个变量的声明。
  • 全局变量泄露。
  • 重新声明只读全局变量和赋值给只读全局变量。

当需要时,有一种显式创建全局变量的方法,即赋值给全局对象的属性。

此规则主要用于浏览器脚本。ES 模块和 CommonJS 模块中的顶层声明创建模块作用域变量。ES 模块也具有隐式的 strict 模式,可防止全局变量泄露。

默认情况下,此规则不检查 constletclass 声明。

此规则有一个对象选项,包含一个选项

  • 如果您希望此规则也检查 constletclass 声明,请将 "lexicalBindings" 设置为 true

规则详情

varfunction 声明

当使用浏览器脚本时,开发者常常忘记顶层作用域中的变量和函数声明会变成 window 对象上的全局变量。这与具有自身作用域的模块相反。如果意图如此,则应将全局变量显式地赋值给 windowself。否则,旨在成为脚本本地变量的变量应包装在 IIFE 中。

此规则禁止在顶层脚本作用域中使用 varfunction 声明。这不适用于 ES 和 CommonJS 模块,因为它们具有模块作用域。

此规则的错误代码示例

在 Playground 中打开
/*eslint no-implicit-globals: "error"*/

var foo = 1;

function bar() {}

此规则的正确代码示例

在 Playground 中打开
/*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" } 时,此规则的正确代码示例

在 Playground 中打开
/*eslint no-implicit-globals: "error"*/

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

全局变量泄露

当代码不在 strict 模式下时,赋值给未声明的变量会创建一个新的全局变量。即使代码在函数中也会发生这种情况。

这不适用于 ES 模块,因为模块代码隐式处于 strict 模式。

此规则的错误代码示例

在 Playground 中打开
/*eslint no-implicit-globals: "error"*/

foo = 1;

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

只读全局变量

此规则还禁止重新声明只读全局变量和赋值给只读全局变量。

只读全局变量可以是内置的 ES 全局变量(例如 Array),也可以是在配置文件或 /*global */ 注释中定义为 readonly 的全局变量。

另请参阅:指定全局变量

此规则的错误代码示例

在 Playground 中打开
/*eslint no-implicit-globals: "error"*/

/*global foo:readonly*/

foo = 1;

Array = [];
var Object;

constletclass 声明

词法声明 constlet,以及 class 声明,创建块级作用域的变量。

但是,当在浏览器脚本的顶层声明时,这些变量不是“脚本作用域”。它们实际上是在全局作用域中创建的,并且可能会与来自其他脚本的 varconstlet 变量以及 functionclass 声明产生名称冲突。这不适用于 ES 和 CommonJS 模块。

如果变量旨在成为脚本本地变量,请用块或立即调用函数表达式 (IIFE) 包裹代码。

"lexicalBindings" 选项设置为 false(默认)时,此规则的正确代码示例

在 Playground 中打开
/*eslint no-implicit-globals: ["error", {"lexicalBindings": false}]*/

const foo = 1;

let baz;

class Bar {}

"lexicalBindings" 选项设置为 true 时,此规则的错误代码示例

在 Playground 中打开
/*eslint no-implicit-globals: ["error", {"lexicalBindings": true}]*/

const foo = 1;

let baz;

class Bar {}

"lexicalBindings" 选项设置为 true 时,此规则的正确代码示例

在 Playground 中打开
/*eslint no-implicit-globals: ["error", {"lexicalBindings": true}]*/

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

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

如果您打算创建一个全局 constlet 变量或全局 class 声明,以便从其他脚本中使用,请注意与传统方法相比存在某些差异,传统方法是 var 声明和赋值给全局 window 对象的属性

  • 词法声明的变量不能有条件地创建。脚本无法检查变量是否存在,然后创建一个新变量。var 变量也始终被创建,但重新声明不会导致运行时异常。
  • 词法声明的变量不会在全局对象上创建属性,这可能是使用脚本所期望的。
  • 词法声明的变量会遮蔽全局对象的属性,如果使用脚本同时使用变量和属性,则可能会产生错误。
  • 如果初始化抛出异常,词法声明的变量可能会产生永久的暂时性死区 (TDZ)。即使是 typeof 检查也不能免受 TDZ 引用异常的影响。

"lexicalBindings" 选项设置为 true 时,此规则的错误代码示例

在 Playground 中打开
/*eslint no-implicit-globals: ["error", {"lexicalBindings": true}]*/

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

"lexicalBindings" 选项设置为 true 时,此规则的正确代码示例

在 Playground 中打开
/*eslint no-implicit-globals: ["error", {"lexicalBindings": true}]*/

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

exported

您可以像在 no-unused-vars 中一样使用 /* exported variableName */ 块注释。有关详细信息,请参阅 no-unused-vars exported 部分

/* exported variableName */ 操作的正确代码示例

在 Playground 中打开
/* eslint no-implicit-globals: error */
/* exported global_var */

var global_var = 42;

何时不使用

在浏览器脚本的情况下,如果您希望能够在全局作用域中显式声明变量和函数,并且您的代码处于严格模式,或者您不希望此规则警告您未声明的变量,并且您也不希望此规则警告您只读全局变量,则可以禁用此规则。

在 CommonJS 模块的情况下,如果您的代码处于严格模式,或者您不希望此规则警告您未声明的变量,并且您也不希望此规则警告您只读全局变量,则可以禁用此规则。

在 ES 模块的情况下,如果您不希望此规则警告您只读全局变量,则可以禁用此规则。

版本

此规则在 ESLint v2.0.0-alpha-1 中引入。

延伸阅读

资源

更改语言