版本

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

變數宣告允許在任何可以放置陳述式的地方,甚至深深地巢狀在其他區塊內。由於變數提升,這通常是不希望發生的,將宣告移動到程式或函數主體的根目錄可以提高清晰度。請注意,區塊綁定letconst)不會被提升,因此它們不受此規則的影響。

// 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 中引入。

資源

變更語言