thisを一言でいうと
JavaScriptにおけるthisは、どこで実行するかで値が変わってしまう、
特殊なキーワードである。
thisを説明しようすると出てくる単語について
thisを理解しようとする時大抵の場合はGoogleしてmozillaの解説を見たりするのだが、
結局以下のような単語も出てきてしまう。するとそれに対する理解も不足していると気づく。
- グローバルオブジェクト
- グローバルコンテキスト
- strictモード
- ブラウザのwindowオブジェクト
...などなど。
周辺知識
この問題を解決するために以下のことを調べた。
実際this自体は「使い所によって意味が変わる」と思っておけばいいのだが、
その意味がどのようになるかを調べる段階で以下のことを知っておく必要がありそうだ。
この記事ではthis自体の意味というよりその周辺知識を見ることに専念する。
- そもそもキーワードって何?
- strictモードって何?
- グローバルオブジェクトって何?
- ブラウザのwindowって何?
- Node.jsとの違いは?
- モジュールシステムって何?
キーワードとは?
大抵のキーワードは、予約されている(= 変数の宣言、関数の宣言の時に使えない)
twitterでidとろうとしたら他のユーザが使っている的なイメージ。
strictモードとは?
別名厳格モード。一部の機能を制限する。
これをオフにするメリット:
未熟な開発者にも優しい言語となり、
エラーとすべき一部の動作が許される。
これをオンにするメリット:
エラーを厳格に出すことでその場で対処することを開発者に強いる。
後々大きな問題になることを未然に防げる。
グローバルオブジェクトとは?
一言で言うとプログラムのどこでも呼び出せるように定義されたオブジェクトのことで、
JavaScriptには必ず設定されている。
ブラウザにおけるWindowオブジェクトとは
「ブラウザのウィンドウ」をJavaScriptで表すためのもの。
(自分たちが見ているブラウザのウィンドウ = Windowオブジェクトでは、必ずしもない。)
その中にDOMが入っている。さらに、DOMの中に入っているdocumentというプロパティが、
ウィンドウの読み込んだDOMの、documentオブジェクトを表している。
DocumentとDOMツリー
DOMツリーとはざっくりいうとHTMLの階層構造をブラウザが解釈するために、
使用するツリー状のデータ構造のことである。
DOMツリーの一番上にあるのがDocumentである。
EventTarget <- Node <- Document
このような関係になっており、DocumentはEventTarget, Nodeのプロパティもうけつぐ。
Node.jsとブラウザの違い
ブラウザではトップレベルのスコープが伝統的にグローバルスコープとなっている。
なのでブラウザのコンソールでvar something
と、コードを実行するとグローバルに変数が作成される。
つまり、window.somethingができる。
一方各Node.jsのファイルは独自のスコープを持つ。
Node.jsのモジュールで、var somethingとすると、
それがCommonJSモジュールにしろ、
ECMAScriptモジュールにしろ、そのモジュールのローカル変数になる。
ECMAScript vs CommonJS
ECMAScriptモジュール(ESM)はES6で導入された、JavaScriptの標準モジュールシステム。
CommonJSはNode.jsで広く使われるモジュールシステム。
ただし、Node.js 12以降であれば、package.jsonに"type": "module"
と設定することでファイルをESMとして扱える。
ESM独自の機能
ESMは非同期でコードを読み込んで、動的にモジュールをインポートすることができる。
未使用のコードをビルドツールが取り除いてくれたりもする。
やっとthisの話をする
非strictモードでの通常の関数の中でthisは、グローバルオブジェクトを指す。
function test() {
console.log(this);
}
test();
ブラウザのコンソールでこれを実行してみるとこうなる。
確かにwindowが返ってきている。
ちなみに厳格モードを使うと同じ関数の結果がundefinedになる。
厳格モードでは、自動的にthisをグローバルオブジェクトに設定するような挙動は、
バグの原因と考えて排除しているわけである。
この記事は非厳格モードで記述されている。
2.オブジェクトのメソッド
として呼ばれると、thisはそのオブジェクト自体を指す。
const obj = {
name: 'Bob',
sayHello: function() {
console.log(`Hello, ${this.name}`);
}
};
obj.sayHello(); // 'Hello, Bob'とコンソールに出る
3.コンストラクタ関数
として呼ばれると、thisはその生成された、インスタンスをさす。
function Person(name) {
this.name = name
}
const alice = new Person('Alice');
console.log(alice.name); // "Alice"