ゼロからはじめるプログラミング講座の第二十二回です。前回、前々回と続き関数のスコープについてやっていきます。グローバル変数へのアクセス、巻き上げ、関数内関数へのアクセスを学びました。
関数スコープの正体を知ろう。
今までブロックだのスコープだの言ってきましたが実は隠してきたことがあります。
#4でブロックとスコープについてこのように書いていました。
{}で囲まれた範囲をブロックと言います。
ブロックで区切ると変数を参照できなくなる場合がある。
前回までの関数を使ったスコープの場合では関数内(ブロック内)の変数に外からアクセスすることができないということは分かりました。
function main(){
var a = 1
}
console.log(a) // 参照エラー
でも今まで学んだ中にブロックを使った構文はもう1つありました。if文です。
if(条件){処理}else{処理}
if文のカッコももちろんブロックですがこのブロックにもスコープは発生するのでしょうか?コードを動かして動作を見ていきましょう。
test.js
if(true){
var a = 1
}else{
var b = 2
}
console.log(a) // 1
console.log(b) // undefined
console.log(c) // 参照エラー
undefined
ReferenceError
if文は条件がtrueで真の処理を通るようになっています。
6行目のコンソールでif(true)ブロック内の変数がきちんと表示されています。
if文の中の変数は外からでも参照可能になっています!
7行目のコンソールではundefined未定義が表示されています。
8行目のコンソールでは存在しない変数cが参照エラーになっています。
以上のことからif文で宣言された変数は分岐を通らなくても存在しているということがわかります。
今までブロックやスコープと曖昧に言ってきましたがここでまとめておきます。
- 関数内の変数には関数スコープという特別な有効範囲がある。
- 関数以外のブロック内(if文など)の変数はどこからでも参照できる。
これはややこしいルールですが、重要なことなのでしっかりと覚えておきましょう。
関数内のif文を調べてみよう。
関数以外には特別なスコープがないことが分かりましたがもう少し動作を確認します。
test.js
function main(){
var a = 1
if(true){
var b = 2
}
console.log(a) // 1
console.log(b) // 2
}
main()
console.log(b) // 参照エラー
2
ReferenceError
7行目のコンソールではif文の中の変数bを参照できています。関数以外のブロックなんだから当然の動作ですね。
しかし10行目関数の外でif文の中の変数bを参照しようとすると参照エラーが出ています。
実はこれも当然の動作なんです。なぜなら変数bがあるif文は関数main()の中にあるからです。関数スコープが働いている変数には外からアクセスできない。でしたね。
関数スコープをマスターしよう。
例題を出すのでコンソールにどのような結果がが表示されるか予測してください。
ややこしいのでよく考えて予測しましょう。
1問目
function main(){
console.log(a)
if(true){
var a = 0
}
console.log(a)
}
main()
マウスオーバーで表示
undefined1
2問目
a = "global"
function main(){
var a = "main"
console.log(a)
if(true){
var a = "if"
console.log(a)
}
console.log(a)
}
main()
console.log(a)
マウスオーバーで表示
mainififglobal
3問目
a = "global"
function main(){
console.log(a)
a = "main"
console.log(a)
}
function sub(){
console.log(a)
a = "sub"
console.log(a)
}
main()
sub()
console.log(a)
マウスオーバーで表示
globalmainmainsubsub
4問目
a = "global"
function main(a){
console.log(a)
a = "main"
console.log(a)
if(true){
a = "if"
console.log(a)
}
console.log(a)
}
main(a)
console.log(a)
マウスオーバーで表示
globalmainififglobal
5問目
a = "global"
function main(){
console.log(a)
a = "main"
console.log(a)
var a = 1
console.log(a)
}
main()
console.log(a)
マウスオーバーで表示
undefinedmain1global
画像で解説を行っています。一部説明してこなかった動作もあります。
2問目
3問目
4問目
5問目
全問理解できましたか?4問目は引数でグローバル変数の値を渡しています。もし引数名をoneに変えて関数内でグローバル変数であるaの値を変更するとグローバル変数aの中身は上書きされれます。引数名がグローバル変数と同じ場合は引数名(変数)が優先されるのでグローバル変数は上書きされません。
お疲れ様でした。これで変数・関数・関数スコープの解説はほぼ終わりました。あと1つ戻り値というものをサ軽く説明して次回以降からループ処理について解説していきます。
次も頑張って記事を作るのでチャレンジしてください!