版本

no-inner-declarations

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

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

// 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 模块的代码)时才成立。在非严格模式下,它们可以在块作用域之外被访问和调用。

"use strict";

if (test) {
    function doSomething () { }

    doSomething(); // no error
}

doSomething(); // error

变量声明允许出现在任何可以放置语句的地方,甚至可以深层嵌套在其他块中。由于变量提升,这通常是不希望看到的,将声明移动到程序或函数体的根部可以提高清晰度。请注意,块绑定 (let, const) 不会被提升,因此它们不受此规则的影响。

// 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;
    }
}

规则详情

此规则要求函数声明以及可选的变量声明位于程序的根部,或函数体的主体根部,或类静态块的主体根部。

选项

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

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

functions

对于使用默认 "functions" 选项的此规则的错误代码示例

在 Playground 中打开
/*eslint no-inner-declarations: "error"*/

// script, non-strict code

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

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

if (foo) function f(){}

对于使用默认 "functions" 选项的此规则的正确代码示例

在 Playground 中打开
/*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" 选项的此规则的错误代码示例

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

在 Playground 中打开
/*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 的此规则的错误代码示例

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

在 Playground 中打开
/*eslint no-inner-declarations: ["error", "functions", { blockScopedFunctions: "disallow" }]*/

function doSomething() { }

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

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

在 Playground 中打开
/*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 模块 以及 class 声明和表达式始终处于严格模式。

在 Playground 中打开
/*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() { }
        }
    }
}

何时不使用

默认情况下,此规则仅禁止在行为未指定且因此不一致(ES6 之前的环境)或应用旧语义(非严格模式代码)的上下文中进行内部函数声明。如果您的代码目标是 ES6 之前的环境或不处于严格模式,则应启用此规则以防止意外行为。

在 ES6+ 环境中,在严格模式代码中,内部函数声明的行为是明确定义的且一致的 - 它们始终是块作用域的。如果您的代码仅以 ES6+ 环境为目标并且处于严格模式(ES 模块,或带有 "use strict" 指令的代码),则无需启用此规则,除非您想禁止内部函数作为一种风格选择,在这种情况下,您应该使用选项 blockScopedFunctions: "disallow" 启用此规则。

当使用 block-scoped-var 时,或者如果即使存在提升,嵌套块中的变量声明也是可以接受的,则禁用检查变量声明。

版本

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

资源

更改语言