JavaScript:お手伝いしているプログラミングスクールで聞かれた質問【thisってどこの事?】

JavaScript:お手伝いしているプログラミングスクールで聞かれた質問【thisってどこの事?】

JavaScript:お手伝いしているプログラミングスクールで聞かれた質問【thisってどこの事?】

プログラミングスクールの生徒さんといろいろお話している中で出てきた『よく理解できなかった事』について、この際まとめておこうの第四弾。
具体的にはこんな内容です。

thisの指す場所は「その時々で変わる」から初心者泣かせである

「thisって何のこと?」今回の質問の中で一番回答に困りました。

勉強していて混乱する理由は『グローバルスコープ』と『コンストラクタ関数』でthisの指すものが変わるからだと思います。でもこれを私自身が初心者がわかる形の明確な言語に出来ない…。
ということで、大まかなところだけお伝えして正確な回答は後日伝えさせていただきました。

そうなんですよね、私も感覚で扱っていて「thisで呼べなかったから、じゃあ変数名で呼び出そう」程度のお付き合いしかしてこなかったのです。まぁ、それでも書けてしまうという事なんですけど、あくまでスクールのお手伝いなのでここは明確にしないとNGです。

まずは大まかな内容で

基本的に英語の【this】と同じです。

this = 今選択しているもの = 今スコープしているオブジェクトの上位オブジェクト

これを理解するには、まず【スコープ】という言葉の理解が必要になります。

クローバルスコープとローカルスコープ

スコープは大別すると【グローバルスコープ】と【ローカルスコープ】の2種類しかありません。
そしてローカルスコープの中に【関数スコープ】【ブロックスコープ】という分類が存在します。

├── ローカルスコープ
|    ├──関数スコープ
|    └──ブロックスコープ
└── グローバルスコープ

絵に書くとこんな感じです。

グローバルスコープとは

プログラムのどこからでもアクセスできる変数の事です。

例えば、JavaScriptのファイルを作成した際にFunctionの中で宣言した変数をfunctionの外で呼び出そうとした時にはエラーが派生しますが、functionの外で宣言した変数をfunction内で利用する場合はエラーが発生しません。(状況にもよりますが)

上の場合、4行目、8行目ともに【global_scope】という文字をコンソールに書きだします。
ちなみに、これはこのように書いても同じです。(ここら辺はfunctionの扱い方ですね)

ローカルスコープとは

先程のScriptをローカルスコープ(functionの中での宣言)にしてみます。※文字だけ変えました。

【’scope’ is not defined】= 「scopeという変数を見つけることができません」というエラーが発生します。
これは上位の変数は下位で読めるけど、下位の変数は上位で読めないという事を意味しています。
という事で『その場固有の変数宣言 = ローカルスコープ』と呼ばれます。

ローカルスコープの関数スコープとは

functionの中で利用されている変数宣言の事を指します。
理解が難しくなるのは多分これ。理由はこんなのが出てくるからです。

これが悩みのポイントになってしまうのは2つの理由があります。

  1. functionの中に記載した変数の値をfunctionの中で取り出せてるじゃん!
  2. function の中で宣言した変数を違うfunctionの中で使ってるじゃん!

後述しますが、ここら辺の思考の組み立てが this に絡んできます。

ローカルスコープのブロックスコープとは

定義としては{ }で囲われた中だけで有効となる変数宣言の事です。

functionも{ } で囲いますから同じような気がしますが、{ } で囲うシーンはfunctionだけでは無いためブロックスコープと呼ばれます。具体的には下のようなif文が良い例でしょうか。

今スコープしているオブジェクトの上位オブジェクトってどういうこと?

話をthisに戻します。こんなコードを書いてみます。

では、上をこんな感じに変えてみます。上のScriptとはtest関数の呼び出し方が変わっています。

objという空のオブジェクトを作成して、そこにtestという値を登録しtest関数をセットしました。
で、object.test()でテスト関数を呼び出しています。

利用しているfunctionのコードは変わらないのに答えがが変わりました。
理由は、最初指示していたthisはグローバルなthisで、次のthisはブロックスコープ内のthisとなっているからです。

この時 this が示しているのはobjというオブジェクトです。それを証明するために下の様に記載してみます。functionの中で呼び出す値をthis.castとして、objに新しい値castを追加しました。

function内では【this.cast】として呼び出し、この結果はobj.castに登録した値『123』がコールされています。つまりこの場合【this.cast = obj.cast】という事ですから【this = obj】という事になります。

ちょっと脱線解説

ちなみに、{test: ƒ}を返しているコードの書き方をこんな風に変えることができます。※同じ意味です。
空のオブジェクト作成して云々という動作をせずに最初からtestを登録した状態でobjを作成しています。

スコープとthisの関係について

もう少し砕いてみます。

この例の場合は、test()のコールはグローバルスコープとなっています。
そのため、thisはグローバルオブジェクトを指すことになります。

一方で、こちらの例ではオブジェクトobjのブロックスコープになっています。スコープされている値はtestですからこの上位のオブジェクトである【obj】が【this】となります。

this = .(ドット)の前の値(オブジェクト)

こう覚えるととても理解しやすいです。

まとめ

thisは文字に起こそうとすると結構難しいですね。
いろんな情報に当たり検証してみると理解が深まっていくと思いますので、たくさんの情報に当たってみましょう。

その他JavaScriptについて受けた質問については個々まとめて行きます。