Index

no-inner-declarations

禁止在嵌套块中声明变量或 function

在 JavaScript 中,在 ES6 之前,函数声明只允许出现在程序的第一层或另一个函数的主体中,尽管解析器有时会错误地在其他地方接受它们。这只适用于函数声明;命名或匿名函数表达式可以出现在允许表达式的任何地方。

🌐 In JavaScript, prior to ES6, a function declaration is only allowed in the first level of a program or the body of another function, though parsers sometimes erroneously accept them elsewhere. This only applies to function declarations; named or anonymous function expressions can occur anywhere an expression is permitted.

// Good
function doSomething() { }

// Bad
if (test) {
    function doSomethingElse () { }
}

function anotherThing() {
    var fn;

    if (test) {

        // Good
        fn = function expression() { };

        // Bad
        function declaration() { }
    }
}

在 ES6 中,块级函数(在块内声明的函数)仅限于它们声明的块作用域,在块作用域之外无法访问和调用这些函数,但仅在代码处于严格模式(带有 "use strict" 标签的代码或 ESM 模块)时才如此。在非严格模式下,它们可以在块作用域之外被访问和调用。

🌐 In ES6, block-level functions (functions declared inside a block) are limited to the scope of the block they are declared in and outside of the block scope they can’t be accessed and called, but only when the code is in strict mode (code with "use strict" tag or ESM modules). In non-strict mode, they can be accessed and called outside of the block scope.

"use strict";

if (test) {
    function doSomething () { }

    doSomething(); // no error
}

doSomething(); // error

变量声明可以出现在语句可以出现的任何地方,即使是深度嵌套在其他块内部。这通常是不理想的,因为变量提升的存在,将声明移动到程序或函数体的根部可以提高清晰度。请注意,块绑定letconst)不会被提升,因此不受此规则影响。

🌐 A variable declaration is permitted anywhere a statement can go, even nested deeply inside other blocks. This is often undesirable due to variable hoisting, and moving declarations to the root of the program or function body can increase clarity. Note that block bindings (let, const) are not hoisted and therefore they are not affected by this rule.

// Good
var foo = 42;

// Good
if (foo) {
    let bar1;
}

// Bad
while (test) {
    var bar2;
}

function doSomething() {
    // Good
    var baz = true;

    // Bad
    if (baz) {
        var quux;
    }
}

规则详情

🌐 Rule Details

该规则要求函数声明和变量声明(可选)位于程序的根目录中,或位于函数主体的根目录中,或位于类静态块主体的根目录中。

🌐 This rule requires that function declarations and, optionally, variable declarations be in the root of a program, or in the root of the body of a function, or in the root of the body of a class static block.

选项

🌐 Options

该规则有一个字符串和一个对象选项:

🌐 This rule has a string and an object option:

  • "functions"(默认)不允许在嵌套块中声明 function
  • "both" 不允许在嵌套块中声明 functionvar
  • { blockScopedFunctions: "allow" }(默认)此选项允许在严格模式下(带有 "use strict" 标签的代码或 ESM 模块)以及 languageOptions.ecmaVersion 设置为 2015 或更高时,在嵌套块中使用 function 声明。可以通过将其设置为 "disallow" 来禁用此选项。

functions

使用默认 "functions" 选项时,该规则的错误代码示例:

🌐 Examples of incorrect code for this rule with the default "functions" option:

在线运行
/*eslint no-inner-declarations: "error"*/

// script, non-strict code

if (test) {
    function doSomething() { }
}

function doSomethingElse() {
    if (test) {
        function doAnotherThing() { }
    }
}

if (foo) function f(){}

使用默认 "functions" 选项时,该规则的正确代码示例:

🌐 Examples of correct code for this rule with the default "functions" option:

在线运行
/*eslint no-inner-declarations: "error"*/

function doSomething() { }

function doSomethingElse() {
    function doAnotherThing() { }
}

function doSomethingElse() {
    "use strict";

    if (test) {
        function doAnotherThing() { }
    }
}

class C {
    static {
        function doSomething() { }
    }
}

if (test) {
    asyncCall(id, function (err, data) { });
}

var fn;
if (test) {
    fn = function fnExpression() { };
}

if (foo) var a;

both

使用 "both" 选项时违反此规则的错误代码示例:

🌐 Examples of incorrect code for this rule with the "both" option:

在线运行
/*eslint no-inner-declarations: ["error", "both"]*/

if (test) {
    var foo = 42;
}

function doAnotherThing() {
    if (test) {
        var bar = 81;
    }
}

if (foo) var a;

if (foo) function f(){}

class C {
    static {
        if (test) {
            var something;
        }
    }
}

使用 "both" 选项时,此规则的正确代码示例:

🌐 Examples of correct code for this rule with the "both" option:

在线运行
/*eslint no-inner-declarations: ["error", "both"]*/

var bar = 42;

if (test) {
    let baz = 43;
}

function doAnotherThing() {
    var baz = 81;
}

class C {
    static {
        var something;
    }
}

blockScopedFunctions

使用 { blockScopedFunctions: "disallow" } 选项和 ecmaVersion: 2015 的此规则的错误代码示例:

🌐 Example of incorrect code for this rule with { blockScopedFunctions: "disallow" } option with ecmaVersion: 2015:

在线运行
/*eslint no-inner-declarations: ["error", "functions", { blockScopedFunctions: "disallow" }]*/

// non-strict code

if (test) {
    function doSomething() { }
}

function doSomething() {
    if (test) {
        function doSomethingElse() { }
    }
}

// strict code

function foo() {
    "use strict";

    if (test) {
        function bar() { }
    }
}

使用 { blockScopedFunctions: "disallow" } 选项和 ecmaVersion: 2015 的此规则的正确代码示例:

🌐 Example of correct code for this rule with { blockScopedFunctions: "disallow" } option with ecmaVersion: 2015:

在线运行
/*eslint no-inner-declarations: ["error", "functions", { blockScopedFunctions: "disallow" }]*/

function doSomething() { }

function doSomething() {
    function doSomethingElse() { }
}

使用 { blockScopedFunctions: "allow" } 选项和 ecmaVersion: 2015 的此规则的正确代码示例:

🌐 Example of correct code for this rule with { blockScopedFunctions: "allow" } option with ecmaVersion: 2015:

在线运行
/*eslint no-inner-declarations: ["error", "functions", { blockScopedFunctions: "allow" }]*/

"use strict";

if (test) {
    function doSomething() { }
}

function doSomething() {
    if (test) {
        function doSomethingElse() { }
    }
}

// OR

function foo() {
    "use strict";

    if (test) {
        function bar() { }
    }
}

ESM modulesclass 的声明和表达式总是在严格模式下。

在线运行
/*eslint no-inner-declarations: ["error", "functions", { blockScopedFunctions: "allow" }]*/

if (test) {
    function doSomething() { }
}

function doSomethingElse() {
    if (test) {
        function doAnotherThing() { }
    }
}

class Some {
    static {
        if (test) {
            function doSomething() { }
        }
    }
}

const C = class {
    static {
        if (test) {
            function doSomething() { }
        }
    }
}

何时不使用

🌐 When Not To Use It

默认情况下,这条规则仅在内部函数声明的行为未指定且因此不一致(ES6 之前的环境)或适用旧语义(非严格模式代码)的情况下禁止它们。如果你的代码针对 ES6 之前的环境或不在严格模式下运行,你应该启用此规则以防止意外行为。

🌐 By default, this rule disallows inner function declarations only in contexts where their behavior is unspecified and thus inconsistent (pre-ES6 environments) or legacy semantics apply (non-strict mode code). If your code targets pre-ES6 environments or is not in strict mode, you should enable this rule to prevent unexpected behavior.

在 ES6 及更高版本的环境中,在严格模式下的代码中,内部函数声明的行为是明确定义且一致的——它们总是块级作用域。如果你的代码仅针对 ES6 及更高版本的环境,并且处于严格模式(ES 模块,或包含 "use strict" 指令的代码),那么没有必要启用此规则,除非你想通过样式选择禁止内部函数,在这种情况下你应该使用选项 blockScopedFunctions: "disallow" 启用此规则。

🌐 In ES6+ environments, in strict mode code, the behavior of inner function declarations is well-defined and consistent - they are always block-scoped. If your code targets only ES6+ environments and is in strict mode (ES modules, or code with "use strict" directives) then there is no need to enable this rule unless you want to disallow inner functions as a stylistic choice, in which case you should enable this rule with the option blockScopedFunctions: "disallow".

在使用 block-scoped-var 时禁用检查变量声明,或者如果在嵌套块中声明变量尽管会提升也可以接受。

🌐 Disable checking variable declarations when using block-scoped-var or if declaring variables in nested blocks is acceptable despite hoisting.

版本

此规则是在 ESLint v0.6.0 中引入。

资源