ゼロからはじめるプログラミング講座の第二十一回です。前回の関数の続きです。関数スコープの範囲をさらに詳しく解説していきます。
関数内からグローバル変数にアクセスしてみよう。
グローバル変数とはvarをつけずに宣言した変数のことだと説明していました。どこからでもアクセスできるのが特徴でした。
それゆえに意図しない変数の中身の書き換えが起こってしまうとも言いました。
関数内ではvarをつけない変数宣言も少し動作が変わってきますので確認しましょう。
test.js
a = "グローバル"
function main(){
var a = 1
console.log(a)
a = 2
console.log(a)
}
main() // 1 2
console.log(a) // グローバル
2
グローバル
1行目で関数の範囲外でグローバル変数a=”グローバル”を作っています。
3行目で関数main()の中でローカル変数a=1を作っています。
4行目のコンソールで指定した変数aはローカル変数か、グローバル変数どちらを参照するでしょうか?結果はローカル変数のa=1が表示されました。
これには巻き上げという動作が起こっているのでローカル変数aが参照されました。
この巻き上げという動作を当たり前の動作だと感じる人とそうでない人がいると思います。当たり前の動作だと感じた人は「コードは上から下へ」のルールを理解しているからだと思います。
実はどちらの感覚も正しいと言えます。コードは上から下へ処理されていきますが、処理をする前に機械は全てのコードを実行する前に確認しています。
関数本体などが良い例です。関数は定義前に実行するコードを書いても問題なく関数が実行されます。このように先に関数を実行しても後に書かれた関数が実行されます。
main() // 1
function main(){ console.log(1) }
話を戻して関数は先に実行しても大丈夫ですが、変数は巻き上げにより上へ上へさかのぼって参照先を探しにしきます。
5行目で変数aの中身を2に変更しています。このaはどこを参照しているのでしょう?
上へさかのぼって見ると3行目にローカル変数aがあるのでこの変数の中身を変更します。
どうでしょうか?巻き上げのイメージがつかめたでしょうか?
今度は先ほどのコードを一行だけ変えて動作を見ます。
test.js
a = "グローバル"
function main(){
//var a = 1
console.log(a)
a = 2
console.log(a)
}
main() // グローバル 2
console.log(a) // 2
2
2
先ほどと結果がガラっと変わりました。まず4行目のコンソールが参照するaは関数main()の中にはありません。なので関数の外にあるグローバル変数まで巻き上げていきます。
グローバル変数の中身は”グローバル”なので「グローバル」が表示されます。
以降も巻き上げで変数aの中身が変わっていきます。
関数内関数を使ってみよう。
巻き上げについてもう少し動作を確認しましょう。そのために関数内関数を使います。
関数内関数とは
用語ではなく単純に関数内に関数を作るだけです。
早速コードを動かしてみましょう。ややこしいので1つずつ参照先を確認しましょう。
test.js
function main(){
var a = 1
console.log(a) // 1
function inner(){
var b = 2
console.log(a) // 1
console.log(b) // 2
}
inner() // 1 2
console.log(b) // 参照エラー
}
main() // 1 1 2 参照エラー
1
2
ReferenceError
2、3行目は問題ないですよね?5-9行目で関数main()の中に関数inner()を作っています。
6行目でローカル変数b=2を作っています。
7行目で変数aを参照しています。巻き上げにより関数inner()の外にある2行目の変数a=1を参照します。ここまでは大丈夫ですか?
12行目変数bを参照したところ参照エラーが出てしまいました。
参照エラーが出たのでコードはこの時点で停止します。
今までの例で上へ巻き上げていけば変数bが参照できそうなものですができません。
理由は変数bは関数inner()のローカル変数だからです。
#4で解説したようにローカル変数はブロックの範囲外からは参照できません。
それは関数内の巻き上げでも同じです。巻き上げて上へ参照先を探していってもブロックの中を通ることはできません。
練習問題を解いてみよう。
変数のスコープのルールを思い出して問題を解きましょう。
- グローバル変数a=1を作りなさい。
- 関数main()を作りローカル変数b=2を作りなさい。
- 関数main()の中に関数inner()を作りコンソールで変数a変数bを表示しなさい。
正解するとこうなります。
解答例はこうです。(マウスオーバーで表示)
a = 1
function main(){
var b = 2
function inner(){
console.log(a,b)
}
inner()
}
main()
全問正解しましたか?グローバル変数はどこからでも参照可能なので関数内関数からも参照可能です。
お疲れ様でした。ブロックとスコープ(有効範囲)はややこしいのですがもう一つ説明することがあるので次回はそれを解説します。
次も頑張って記事を作るのでチャレンジしてください!
JavaScript #1/#2/#3/#4/#5/#6/#7/#8/#9/#10/#11/#12/#13/#14/#15/#16/#17/#18/#19/#20
_(__つ/ ̄ ̄ ̄/
\/ /
 ̄ ̄ ̄
(´・ω・`)
_( つ ミ バタンッ
\ ̄ ̄ ̄\ミ
 ̄ ̄ ̄ ̄