版本

no-invalid-this

禁止在 this 值為 undefined 的情況下使用 this

在嚴格模式下,類別或類別物件之外的 this 關鍵字可能會是 undefined 並引發 TypeError

規則詳情

此規則旨在標記在 this 值為 undefined 的情況下使用 this 關鍵字。

腳本中的頂層 this 始終被視為有效,因為無論是否為嚴格模式,它都指向全域物件。

ECMAScript 模組中的頂層 this 始終被視為無效,因為其值為 undefined

對於函式內的 this,此規則基本上會檢查包含 this 關鍵字的函式是否為建構子或方法。請注意,箭頭函式具有詞法 this,因此此規則會檢查它們的封閉環境。

此規則根據以下條件判斷函式是否為建構子

  • 函式的名稱以大寫字母開頭。
  • 函式被賦值給一個以大寫字母開頭的變數。
  • 函式是 ES2015 類別的建構子。

此規則根據以下條件判斷函式是否為方法

  • 函式位於物件字面值上。
  • 函式被賦值給一個屬性。
  • 函式是 ES2015 類別的方法/getter/setter。

且此規則允許在以下函式中使用 this 關鍵字

  • 直接呼叫函式的 call/apply/bind 方法。
  • 如果給定了 thisArg,則函式是陣列方法(例如 .forEach())的回呼。
  • 函式的 JSDoc 註解中包含 @this 標籤。

且此規則始終允許在以下情況下使用 this 關鍵字

  • 在腳本的頂層。
  • 在類別欄位初始化器中。
  • 在類別靜態區塊中。

否則將被視為問題。

此規則在嚴格模式下適用。在 ESLint 設定中使用 "parserOptions": { "sourceType": "module" },即使沒有 "use strict" 指令,您的程式碼也處於嚴格模式。

在嚴格模式下,此規則的錯誤程式碼範例

在 Playground 中開啟
/*eslint no-invalid-this: "error"*/

"use strict";

(function() {
    this.a = 0;
    baz(() => this);
})();

function foo() {
    this.a = 0;
    baz(() => this);
}

const bar = function() {
    this.a = 0;
    baz(() => this);
};

foo(function() {
    this.a = 0;
    baz(() => this);
});

const obj = {
    aaa: function() {
        return function foo() {
            // There is in a method `aaa`, but `foo` is not a method.
            this.a = 0;
            baz(() => this);
        };
    }
};

foo.forEach(function() {
    this.a = 0;
    baz(() => this);
});

在嚴格模式下,此規則的正確程式碼範例

在 Playground 中開啟
/*eslint no-invalid-this: "error"*/

"use strict";

this.a = 0;
baz(() => this);

function Foo() {
    // OK, this is in a legacy style constructor.
    this.a = 0;
    baz(() => this);
}

class Bar {
    constructor() {
        // OK, this is in a constructor.
        this.a = 0;
        baz(() => this);
    }
}

const obj = {
    foo: function foo() {
        // OK, this is in a method (this function is on object literal).
        this.a = 0;
    }
};

const obj1 = {
    foo() {
        // OK, this is in a method (this function is on object literal).
        this.a = 0;
    }
};

const obj2 = {
    get foo() {
        // OK, this is in a method (this function is on object literal).
        return this.a;
    }
};

const obj3 = Object.create(null, {
    foo: {value: function foo() {
        // OK, this is in a method (this function is on object literal).
        this.a = 0;
    }}
});

Object.defineProperty(obj, "foo", {
    value: function foo() {
        // OK, this is in a method (this function is on object literal).
        this.a = 0;
    }
});

Object.defineProperties(obj, {
    foo: {value: function foo() {
        // OK, this is in a method (this function is on object literal).
        this.a = 0;
    }}
});

function Foo() {
    this.foo = function foo() {
        // OK, this is in a method (this function assigns to a property).
        this.a = 0;
        baz(() => this);
    };
}

obj.foo = function foo() {
    // OK, this is in a method (this function assigns to a property).
    this.a = 0;
};

Foo.prototype.foo = function foo() {
    // OK, this is in a method (this function assigns to a property).
    this.a = 0;
};

class Baz {

    // OK, this is in a class field initializer.
    a = this.b;

    // OK, static initializers also have valid this.
    static a = this.b;

    foo() {
        // OK, this is in a method.
        this.a = 0;
        baz(() => this);
    }

    static foo() {
        // OK, this is in a method (static methods also have valid this).
        this.a = 0;
        baz(() => this);
    }

    static {
        // OK, static blocks also have valid this.
        this.a = 0;
        baz(() => this);
    }
}

const bar = (function foo() {
    // OK, the `bind` method of this function is called directly.
    this.a = 0;
}).bind(obj);

foo.forEach(function() {
    // OK, `thisArg` of `.forEach()` is given.
    this.a = 0;
    baz(() => this);
}, thisArg);

/** @this Foo */
function foo() {
    // OK, this function has a `@this` tag in its JSDoc comment.
    this.a = 0;
}

選項

此規則有一個物件選項,只有一個選項

  • "capIsConstructor": false(預設為 true)停用名稱以大寫字母開頭的函式是建構子的假設。

capIsConstructor

預設情況下,此規則始終允許在名稱以大寫字母開頭的函式以及賦值給名稱以大寫字母開頭的變數的匿名函式中使用 this,假設這些函式用作建構函式。

如果您希望將這些函式視為「常規」函式,請將 "capIsConstructor" 設定為 false

"capIsConstructor" 選項設定為 false 的情況下,此規則的錯誤程式碼範例

在 Playground 中開啟
/*eslint no-invalid-this: ["error", { "capIsConstructor": false }]*/

"use strict";

function Foo() {
    this.a = 0;
}

const bar = function Foo() {
    this.a = 0;
}

const Bar = function() {
    this.a = 0;
};

Baz = function() {
    this.a = 0;
};

"capIsConstructor" 選項設定為 false 的情況下,此規則的正確程式碼範例

在 Playground 中開啟
/*eslint no-invalid-this: ["error", { "capIsConstructor": false }]*/

"use strict";

obj.Foo = function Foo() {
    // OK, this is in a method.
    this.a = 0;
};

何時不該使用

如果您不希望收到關於在類別或類別物件之外使用 this 關鍵字的通知,您可以安全地停用此規則。

由 TypeScript 處理

當使用 TypeScript 時,停用此規則是安全的,因為 TypeScript 的編譯器會強制執行此檢查。

請注意,從技術上講,只有在您啟用 strictnoImplicitThis 旗標時,TypeScript 才會捕捉到這一點。這些在大多數 TypeScript 專案中都是啟用的,因為它們被認為是最佳實踐。

版本

此規則在 ESLint v1.0.0-rc-2 中引入。

資源

變更語言