このキーワード

キーワード this は、呼び出し時に関数にバインドされるオブジェクトの値を指します。つまり、関数がメソッドとして呼び出されるか、スタンドアロン関数として呼び出されるか、コンストラクタとして呼び出されるかによって値が異なります。

関数が呼び出されると、その関数を含むオブジェクトへの参照として、キーワード this のインスタンスが非表示で作成され、そのスコープ内から、その関数とともに定義されたプロパティとメソッドにアクセスできるようになります。this の操作は、const で宣言された変数の操作といくつかの点で似ています。定数と同様に、this は削除できず、その値を再代入することはできませんが、this キーワードを含むオブジェクトのメソッドとプロパティは変更できます。

グローバル バインディング

関数やオブジェクトのコンテキスト外では、thisglobalThis プロパティを参照します。これは、ほとんどの JavaScript 環境のグローバル オブジェクトへの参照です。ウェブブラウザで実行されるスクリプトのコンテキストでは、グローバル オブジェクトは window オブジェクトです。

this;
> Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, ...}

Node.js では、globalThisglobal オブジェクトです。

$ node
Welcome to Node.js v20.10.0.
Type ".help" for more information.
> this
<ref *1> Object [global] {
...
}

厳格モード以外では、this はスタンドアロン関数内のグローバル オブジェクトも参照します。これは、親 Window がこれらの関数を事実上「所有」するオブジェクトであるためです。

function myFunction() {
    console.log( this );
}
myFunction();
> Window {...}

(function() {
    console.log( this );
}());
> Window {...}

厳格モードを使用する場合、this はスタンドアロン関数内で undefined の値になります。

(function() {
    "use strict";
    console.log( this );
}());
> undefined

厳格モードが導入される前は、thisnull 値または undefined 値は、グローバル オブジェクトへの参照に置き換えられていました。この従来型の動作により、グローバル バインディングは「デフォルト バインディング」と呼ばれることがあります。

暗黙的なバインディング

関数がオブジェクトのメソッドとして呼び出されると、そのメソッド内の this のインスタンスは、そのメソッドを含むオブジェクトを参照し、そのメソッドとプロパティにアクセスできます。

let myObject = {
    myValue: "This is my string.",
    myMethod() {
            console.log( this.myValue );
    }
};

myObject.myMethod();
> "This is my string."

this の値は、関数とその包含オブジェクトの定義方法によって異なるように見えます。代わりに、this の値のコンテキストは現在の実行コンテキストです。この場合、実行コンテキストは、myObject オブジェクトが myMethod メソッドを呼び出しているため、myObjectthis の値です。これは、前述の例のコンテキストでは技術的な問題のように思えますが、this をより高度に使用する場合、これは重要な区別です。

通常、this は、周囲のコードに特定の構造があることを想定しない方法で使用します。このルールの例外は、ES5 の矢印関数です。

アロー関数での this

矢印関数では、this字句的包含環境内のバインディングに解決されます。つまり、矢印関数の this は、その関数を最も近い囲むコンテキスト内の this の値を参照します。

let myObject = {
    myMethod() { console.log( this ); },
    myArrowFunction: () => console.log( this ),
    myEnclosingMethod: function () {
        this.myArrowFunction = () => { console.log(this) };
    }
};

myObject.myMethod();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }

myObject.myArrowFunction();
> Window {...}

上の例では、myObject.myMethod() は、そのメソッドを「所有」するオブジェクトとして myObject をログに記録しますが、myObject.myArrowFunction()globalThis(または undefined)を返します。これは、矢印関数内の this のインスタンスが、最も外側のスコープを参照するためです。

次の例では、myEnclosingMethod は実行時に、そのオブジェクトに矢印関数を作成します。アロー関数内の this のインスタンスは、そのアロー関数を含むメソッドである、囲む環境内の this の値を参照するようになりました。myEnclosingMethod 内の this の値は myObject を参照するため、矢印関数を定義すると、矢印関数内の thismyObject を参照します。

let myObject = {
    myMethod() { console.log( this ); },
    myEnclosingMethod: function () {
        this.myArrowFunction = () => { console.log(this) };
    }
};

myObject.myEnclosingMethod();
myObject.myArrowFunction();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }

明示的なバインディング

暗黙的なバインディングは、this を操作するほとんどのユースケースを処理します。ただし、想定されるコンテキストではなく、特定の実行コンテキストを表すために this の値が必要になる場合があります。少し古い例ですが、setTimeout のコールバック関数内で this を操作しています。このコールバックには一意の実行コンテキストがあります。

var myObject = {
  myString: "This is my string.",
  myMethod() {
    console.log( this.myString );
  }
};
myObject.myMethod();
> "This is my string."

setTimeout( myObject.myMethod, 100 );
> undefined

setTimeout のこの特定の欠点は、その後他の機能によって対処されていますが、this が「失われる」という同様の問題は、意図したコンテキストのスコープ内で this の値への明示的な参照を作成することで対処されていました。レガシー コードベースでは、thatself_this などの識別子を使用して this のインスタンスが変数に割り当てられていることがあります。これらは、渡された this 値を含む変数に使用される一般的な識別子規則です。

call()bind()apply() メソッドを使用して関数を呼び出すと、this は呼び出されるオブジェクトを明示的に参照します。

let myFunction = function() {
    console.log( this.myValue );
}

let myObject = {
   "myValue" : "This is my string."
 };

myFunction.call( myObject );
> "This is my string."
var myObject = {
  myString: "This is my string.",
  myMethod() {
    console.log( this.myString );
  }
};

setTimeout( myObject.myMethod.bind( myObject ), 100 );
> "This is my string."

明示的なバインディングは、暗黙的なバインディングによって提供される this 値をオーバーライドします。

let myObject = {
    "myValue" : "This string sits alongside myMethod.",
    myMethod() {
        console.log( this.myValue );
    }
};
let myOtherObject = {
    "myValue" : "This is a string in another object entirely.",
};

myObject.myMethod.call( myOtherObject );
> "This is a string in another object entirely."

this の値が undefined または null に設定されるように関数が呼び出されると、その値は厳格モード以外で globalThis に置き換えられます。

let myFunction = function() {
    console.log( this );
}

myFunction.call( null );
> Window {...}

同様に、this にプリミティブ値を渡すように関数が呼び出されると、その値は厳格モード外でプリミティブ値のラッパー オブジェクトに置き換えられます。

let myFunction = function() {
    console.log( this );
}

let myNumber = 10;

myFunction.call( myNumber );
> Number { 10 }

厳格モードでは、渡された this 値は、プリミティブ値、null 値、undefined 値であっても、オブジェクトに強制変換されません。

"use strict";
let myFunction = function() {
    console.log( this );
}

let myNumber = 10;

myFunction.call( myNumber );
> 10

myFunction.call( null );
> null

new バインディング

new キーワードを使用してコンストラクタとしてクラスを使用する場合、this は新しく作成されたインスタンスを参照します。

class MyClass {
    myString;
    constructor() {
        this.myString = "My string.";
    }
    logThis() {
        console.log( this );
    }
}
const thisClass = new MyClass();

thisClass.logThis();
> Object { myString: "My string." }

同様に、new を使用して呼び出されたコンストラクタ関数内の this の値は、作成されるオブジェクトを参照します。

function MyFunction() {
  this.myString = "My string.";
  this.logThis = function() {
    console.log( this );
  }
}
const myObject = new MyFunction();

myObject.logThis();
> Object { myString: "My string.", logThis: logThis() }

イベント ハンドラのバインディング

イベント ハンドラのコンテキストでは、this の値は、それを呼び出すオブジェクトを参照します。イベント ハンドラのコールバック関数内では、this はハンドラに関連付けられた要素を参照します。

let button = document.querySelector( "button" );

button.addEventListener( "click", function( event ) { console.log( this ); } );

ユーザーが前のスニペットの button を操作すると、結果として <button> 自体を含む要素オブジェクトが返されます。

> Button {}

アロー関数をイベント リスナー コールバックとして使用する場合、this の値は、最も近い包含実行コンテキストによって再度提供されます。最上位レベルでは、イベント ハンドラ コールバック関数内の thisglobalThis です。

let button = document.querySelector( "button" );

button.addEventListener( "click", ( event ) => { console.log( this ); } );
> undefined

他のオブジェクトと同様に、call()bind()、または apply() メソッドを使用してイベント リスナーのコールバック関数を参照する場合、this はオブジェクトを明示的に参照します。

let button = document.querySelector( "button" );
let myObject = {
    "myValue" : true
};
function handleClick() {
    console.log( this );
}

button.addEventListener( "click", handleClick.bind( myObject ) );
> Object { myValue: true }

理解度を確認する

ウェブブラウザで実行されるスクリプトの場合、関数やオブジェクトのコンテキストの外部で使用されたときに this が参照するグローバル オブジェクトは何ですか。

window オブジェクト
browser オブジェクト
undefined オブジェクト