JavaScriptにおけるコンテキストの喪失
関数内に関数がある場合を考えましょう。
外側の関数をparent、内側の関数をchildと呼ぶことにします:
function parent() {
function child() {
}
}
前回のレッスンから、外側の関数で変数を定義すると、内側の関数からその変数にアクセスできることをご存知でしょう:
function parent() {
let str = 'abcde';
function child() {
console.log(str); // 'abcde' を出力
}
child(); // 内側の関数を呼び出す
}
parent(); // 外側の関数を呼び出す
しかし、注意点があります:内側の関数は外側の関数のすべての変数にはアクセスできますが、thisにはアクセスできません。つまり、外側の関数が何らかのDOM要素にバインドされている場合、その中のthisはその要素を指しますが、内側の関数のthisは指しません!
では、内側の関数のthisは何を指すのでしょうか?答え:それはundefinedになります(厳格モードでは)。なぜなら、関数は何にもバインドされていないからです。
実際に確認してみましょう。ここにinput要素があるとします:
<input id="elem" value="text">
このinput要素に、フォーカスが外れたときに呼び出される関数parentをバインドしましょう:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
// フォーカスが外れたときに呼び出される:
function parent() {
// ここに何らかのコード
function child() {
// ここに何らかのコード
}
child(); // 子関数を呼び出す
}
二箇所でthisの内容をコンソールに出力してみましょう:parent関数内とchild関数内です:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
function parent() {
console.log(this); // input要素への参照を出力
function child() {
console.log(this); // undefined を出力
}
child();
}
このコードを実行し、input要素のフォーカスを外してコンソールを確認してください。最初のconsole.logはinput要素への参照を出力し、二つ目は単にundefinedを出力することがわかります。このように、thisが予期せず必要なものを指さない状況を、コンテキストの喪失と呼びます。
ここで、両方の関数でinputのvalueを出力するように変更します。コメントで示された行で何が出力されるか確認してください:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
function parent() {
console.log(this.value); // 何が出力される?
function child() {
console.log(this.value); // 何が出力される?
}
child();
}