JavaScript:お手伝いしているプログラミングスクールで聞かれた質問【thisってどこの事?】
- 2021.04.12
- JavaScript備忘録
- JavaScript, this, スクリプト備忘録, スコープ, ひとりごと, 初心者, 変数宣言
JavaScript:お手伝いしているプログラミングスクールで聞かれた質問【thisってどこの事?】
プログラミングスクールの生徒さんといろいろお話している中で出てきた『よく理解できなかった事』について、この際まとめておこうの第四弾。
具体的にはこんな内容です。
thisの指す場所は「その時々で変わる」から初心者泣かせである
「thisって何のこと?」今回の質問の中で一番回答に困りました。
勉強していて混乱する理由は『グローバルスコープ』と『コンストラクタ関数』でthisの指すものが変わるからだと思います。でもこれを私自身が初心者がわかる形の明確な言語に出来ない…。
ということで、大まかなところだけお伝えして正確な回答は後日伝えさせていただきました。
そうなんですよね、私も感覚で扱っていて「thisで呼べなかったから、じゃあ変数名で呼び出そう」程度のお付き合いしかしてこなかったのです。まぁ、それでも書けてしまうという事なんですけど、あくまでスクールのお手伝いなのでここは明確にしないとNGです。
まずは大まかな内容で
基本的に英語の【this】と同じです。
this = 今選択しているもの = 今スコープしているオブジェクトの上位オブジェクト
これを理解するには、まず【スコープ】という言葉の理解が必要になります。
クローバルスコープとローカルスコープ
スコープは大別すると【グローバルスコープ】と【ローカルスコープ】の2種類しかありません。
そしてローカルスコープの中に【関数スコープ】【ブロックスコープ】という分類が存在します。
| ├──関数スコープ
| └──ブロックスコープ
└── グローバルスコープ
絵に書くとこんな感じです。
グローバルスコープとは
プログラムのどこからでもアクセスできる変数の事です。
例えば、JavaScriptのファイルを作成した際にFunctionの中で宣言した変数をfunctionの外で呼び出そうとした時にはエラーが派生しますが、functionの外で宣言した変数をfunction内で利用する場合はエラーが発生しません。(状況にもよりますが)
1 2 3 4 5 6 7 8 9 |
var scope = 'global_scope'; // トップレベルからのアクセス console.log(scope); // 関数内からのアクセス (function () { console.log(scope); })(); |
上の場合、4行目、8行目ともに【global_scope】という文字をコンソールに書きだします。
ちなみに、これはこのように書いても同じです。(ここら辺はfunctionの扱い方ですね)
1 2 3 4 5 6 7 8 9 10 |
var scope = 'global_scope'; // トップレベルからのアクセス console.log(scope); // 関数内からのアクセス test(); function test() { console.log(scope); } |
ローカルスコープとは
先程のScriptをローカルスコープ(functionの中での宣言)にしてみます。※文字だけ変えました。
1 2 3 4 5 6 7 8 |
function test() { var scope = 'local_scope'; console.log(scope); } // トップレベルからのアクセス console.log(scope); # 結果 => 'scope' is not defined |
【’scope’ is not defined】= 「scopeという変数を見つけることができません」というエラーが発生します。
これは上位の変数は下位で読めるけど、下位の変数は上位で読めないという事を意味しています。
という事で『その場固有の変数宣言 = ローカルスコープ』と呼ばれます。
ローカルスコープの関数スコープとは
functionの中で利用されている変数宣言の事を指します。
理解が難しくなるのは多分これ。理由はこんなのが出てくるからです。
1 2 3 4 5 6 7 8 9 10 |
function test() { var scope = 'local_scope'; function test2() { console.log(scope); } test2(); } test(); # 結果 => 'local_scope' |
これが悩みのポイントになってしまうのは2つの理由があります。
- functionの中に記載した変数の値をfunctionの中で取り出せてるじゃん!
- function の中で宣言した変数を違うfunctionの中で使ってるじゃん!
後述しますが、ここら辺の思考の組み立てが this に絡んできます。
ローカルスコープのブロックスコープとは
定義としては{ }で囲われた中だけで有効となる変数宣言の事です。
functionも{ } で囲いますから同じような気がしますが、{ } で囲うシーンはfunctionだけでは無いためブロックスコープと呼ばれます。具体的には下のようなif文が良い例でしょうか。
1 2 3 4 5 6 |
let test = 1; if ( test == 1){ let val = 'ブロックスコープです' }else{ let val = 'これもブロックスコープです' } |
今スコープしているオブジェクトの上位オブジェクトってどういうこと?
話をthisに戻します。こんなコードを書いてみます。
1 2 3 4 5 6 |
function test(){ console.log(this); } test(); # 結果 => Window {0: Window, window: Window, self: Window, document: document, name: "", location: Location, …} |
では、上をこんな感じに変えてみます。上のScriptとはtest関数の呼び出し方が変わっています。
1 2 3 4 5 6 7 8 9 |
function test() { console.log(this); } var obj = {}; obj.test = test; obj.test(); # 結果 => {test: ƒ} |
objという空のオブジェクトを作成して、そこにtestという値を登録しtest関数をセットしました。
で、object.test()でテスト関数を呼び出しています。
利用しているfunctionのコードは変わらないのに答えがが変わりました。
理由は、最初指示していたthisはグローバルなthisで、次のthisはブロックスコープ内のthisとなっているからです。
この時 this が示しているのはobjというオブジェクトです。それを証明するために下の様に記載してみます。functionの中で呼び出す値をthis.castとして、objに新しい値castを追加しました。
1 2 3 4 5 6 7 8 9 |
function test() { console.log(this.cast); } var obj = {}; obj.test = test; obj.cast = '123'; obj.test() # 結果 => 123 |
function内では【this.cast】として呼び出し、この結果はobj.castに登録した値『123』がコールされています。つまりこの場合【this.cast = obj.cast】という事ですから【this = obj】という事になります。
ちょっと脱線解説
ちなみに、{test: ƒ}を返しているコードの書き方をこんな風に変えることができます。※同じ意味です。
空のオブジェクト作成して云々という動作をせずに最初からtestを登録した状態でobjを作成しています。
1 2 3 4 5 6 7 |
function test() { console.log(this); } var obj = {test:test}; obj.test() # 結果 => {test: ƒ} |
スコープとthisの関係について
もう少し砕いてみます。
1 2 3 4 5 |
function test(){ console.log(this); } test(); |
この例の場合は、test()のコールはグローバルスコープとなっています。
そのため、thisはグローバルオブジェクトを指すことになります。
1 2 3 4 5 6 7 |
function test() { console.log(this); } var obj = {}; obj.test = test; obj.test(); |
一方で、こちらの例ではオブジェクトobjのブロックスコープになっています。スコープされている値はtestですからこの上位のオブジェクトである【obj】が【this】となります。
this = .(ドット)の前の値(オブジェクト)
こう覚えるととても理解しやすいです。
まとめ
thisは文字に起こそうとすると結構難しいですね。
いろんな情報に当たり検証してみると理解が深まっていくと思いますので、たくさんの情報に当たってみましょう。
その他JavaScriptについて受けた質問については個々まとめて行きます。
-
前の記事
JavaScript:お手伝いしているプログラミングスクールで聞かれた質問【オブジェクトって何?】 2021.04.06
-
次の記事
JavaScript:お手伝いしているプログラミングスクールで聞かれた質問【JavaScriptはJava?】 2021.04.13
コメントを残す