はじめに
JavaScriptのthisの挙動がわからないとTwitterで嘆いていたところ、JavaScriptに詳しい知人がわかりやすい資料を共有してくれました。
関数とメソッド編/Arrow Function編に分けて自分のために整理しようと思います。
(この記事では、strictモードを使った場合を想定しています。)
読んだもの
JavaScriptの入門書 - 関数とthis
最強オブジェクト指向言語 JavaScript 再入門!
thisの基本
thisは、関数が呼び出されたときにその関数が所属していたオブジェクトを指します。 つまり、呼び出されるときに初めて値が決まります。
const person = {
name : '太郎',
sayHello() {
console.log('Hello, ' + this.name);
}
};
person.sayHello();
// => Hello, 太郎
この場合のthisはpersonオブジェクトです。
このように、メソッドが所属するオブジェクトのプロパティを、オブジェクト名.プロパティ名(person.name)の代わりにthis.プロパティ名(this.name)で参照できます。
問題が発生する場合
1. thisを含むメソッドを変数に代入した場合
personオブジェクトのsayHelloメソッドを、変数sayに関数として代入してから実行してみます。
"use strict";
const person = {
name : '太郎',
sayHello() {
console.log('Hello, ' + this.name);
}
};
const say = person.sayHello;
say();
// => TypeError: Cannot read property 'name' of undefined
say関数はsayHelloメソッドを参照しており、sayHelloメソッドはpersonオブジェクトに所属しています。 しかし、say関数には所属するオブジェクトがありません。
// ココ
say();
このため、say関数が呼び出された際にsayHelloメソッド内のthisはundefinedとなり、エラーが発生します。
2. コールバック関数の中でthisを参照する場合
printNameメソッドの中でArray#mapメソッドを使ってみます。
"use strict";
const person = {
suffix: "さん",
printName(names) {
return names.map(function(name) {
return name + this.suffix;
});
}
};
person.printName(["太郎", "二郎", "三郎"]);
// => TypeError: Cannot read property 'suffix' of undefined
printNameメソッドで、thisは定義時にはpersonを指しています。 しかし、Array#mapメソッドを呼び出すときに、コールバック関数として匿名関数を渡しています。
// ココ
return names.map(function(name) {
このとき、匿名関数が所属するオブジェクトはないので、thisがundefindになり、this.nameを呼び出せずエラーが発生します。
おわりに
次回はArrow Function編です。