キーワード this
は、呼び出し時に関数にバインドされるオブジェクトの値を指します。つまり、関数がメソッドとして呼び出されるか、スタンドアロン関数として呼び出されるか、コンストラクタとして呼び出されるかによって値が異なります。
関数が呼び出されると、その関数を含むオブジェクトへの参照として、キーワード this
のインスタンスが非表示で作成され、そのスコープ内から、その関数とともに定義されたプロパティとメソッドにアクセスできるようになります。this
の操作は、const
で宣言された変数の操作といくつかの点で似ています。定数と同様に、this
は削除できず、その値を再代入することはできませんが、this
キーワードを含むオブジェクトのメソッドとプロパティは変更できます。
グローバル バインディング
関数やオブジェクトのコンテキスト外では、this
は globalThis
プロパティを参照します。これは、ほとんどの JavaScript 環境のグローバル オブジェクトへの参照です。ウェブブラウザで実行されるスクリプトのコンテキストでは、グローバル オブジェクトは window
オブジェクトです。
this;
> Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, ...}
Node.js では、globalThis
は global
オブジェクトです。
$ 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
厳格モードが導入される前は、this
の null
値または undefined
値は、グローバル オブジェクトへの参照に置き換えられていました。この従来型の動作により、グローバル バインディングは「デフォルト バインディング」と呼ばれることがあります。
暗黙的なバインディング
関数がオブジェクトのメソッドとして呼び出されると、そのメソッド内の this
のインスタンスは、そのメソッドを含むオブジェクトを参照し、そのメソッドとプロパティにアクセスできます。
let myObject = {
myValue: "This is my string.",
myMethod() {
console.log( this.myValue );
}
};
myObject.myMethod();
> "This is my string."
this
の値は、関数とその包含オブジェクトの定義方法によって異なるように見えます。代わりに、this
の値のコンテキストは現在の実行コンテキストです。この場合、実行コンテキストは、myObject
オブジェクトが myMethod
メソッドを呼び出しているため、myObject
は this
の値です。これは、前述の例のコンテキストでは技術的な問題のように思えますが、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
を参照するため、矢印関数を定義すると、矢印関数内の this
も myObject
を参照します。
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
の値への明示的な参照を作成することで対処されていました。レガシー コードベースでは、that
、self
、_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
の値は、最も近い包含実行コンテキストによって再度提供されます。最上位レベルでは、イベント ハンドラ コールバック関数内の this
は globalThis
です。
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
オブジェクト