キーワード 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 {...}
strict モードを使用する場合、スタンドアロン関数内の 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
arrow 関数では、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 }
strict モードでは、渡された 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
(厳格モードでは undefined
)です。
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
オブジェクト