【JavaScript】スコープを意識して保守性の高いコードを作ろう!
エンジニアになろう!
JavaScriptのスコープについて
『スコープ』とは、変数や関数の有効範囲のことです。
関数や変数は、定義されたスコープ内でしか影響を与えることが出来ません。
スコープとはなぜ必要なのか、どうやって使うのかを解説します。
まずはこちらのサンプルコードをご覧ください
1function func() {
2 var hello = "hello world"
3}
4func()
5console.log(hello); // => error
【実行結果】
ReferenceError: hello is not defined
上記のサンプルでは、関数 func() の中で 変数 hello を定義し、関数 func() 外から変数 hello を呼び出そうとしています。
実行すると ReferenceError: hello is not defined とエラーが表示されてしまいました。
「変数 hello は定義されていない」と怒られてしまいます。
次にこちらのサンプルコードをご覧ください
1function func() {
2 var hello = "hello world"
3 console.log(hello);
4}
5func()
【実行結果】
hello world
上記のサンプルでは、関数 func() の中で、 変数 hello を定義し、関数 func() 内から変数 hello を呼び出そうとしています。
今回は、エラーがでることもなくメッセージを表示できました。
つまり、関数内で定義された変数は、関数内でしか実行できません。
関数内で定義された変数は、関数内でしか実行できない
関数内の変数の記憶領域は、関数が終了時に破棄されます。
そのため、一番最初で示したサンプルコードではエラーが表示されました。
異なる関数で同名のの変数やオブジェクトを定義しても、それは別物として扱われます。
1function func0() {
2 var hello = "hello world"
3 console.log(hello);
4}
5
6function func1() {
7 var hello = 'HEY!'
8 console.log(hello);
9}
10
11func0() // => hello world
12func1() // => HEY!
1. グローバルスコープ
2. 関数スコープ
3. ブロックスコープ ( ES2015/ES6 以降)
グローバルスコープ
グローバルスコープとは、関数の外(トップレベル)で定義した変数、関数になります。
また var をつけずに変数を定義した場合も、グローバルスコープの変数になります。
グローバル関数
グローバルスコープの変数、関数をグローバル変数、グローバル関数と言います。
グローバルスコープの変数は、プログラムのどこからでも呼び出すことができ、値を変更することもできます。
どこからでもアクセスできるため、プログラムが大きくなればなるほどに影響範囲が大きくなります。
サンプルコード
1var globalScope = 'global';
2
3// グローバル関数
4function globalFunc() {
5 console.log('this is ' + globalScope)
6}
7
8// グローバル変数、グローバル関数はどこでも呼び出せるし、変更できる。
9globalFunc(); // => this is global
10globalScope = 'global2';
11globalFunc(); // => this is global2
グローバル変数globalScopeを、関数globalFunc()で呼び出しています。
その後、変数の値を変更しています。
【実行結果】
this is global
this is global2
変数の中身は変更されていることが確認できます。
注意事項
グローバル変数は極力使わないようにプログラムを作成してください。
なぜならグローバル変数の値を変更した場合、プログラム全体に影響を及ぼします。
影響範囲が広いということは、なにかバグが発生しやすくなります。
また、ソースコードを改修するときに、調べなければならない範囲が広いことになり、プログラムの保守性が低下します。
関数スコープ(ローカルスコープ)
関数スコープとは、関数の中で定義した変数、関数です。
関数内の中だけその変数を利用することができます。
変数の影響範囲が関数内に限られるため、プログラム全体への影響を抑えることができます。
サンプルコード
1// グローバル関数
2function globalFunc() {
3 // ローカル変数
4 var localScope = "local";
5 console.log('This is ' + localScope);
6}
7
8// ローカル変数を呼びだす
9globalFunc(); // => This is localVal
10
11// ローカル変数をスコープ外から呼び出し。スコープ外なので利用できない
12console.log(localScope) // => error : undefined
関数 globalFunc() の中でローカル変数 localScope を呼び出しています。
また、関数globalFunc() の外から、ローカル変数 localScope を呼び出しています。
【実行結果】
This is local
ReferenceError: localScope is not defined
実行結果をみると、スコープ外からローカル変数localVal を呼び出していたためエラーがでています。
ローカル変数の影響範囲が限定的であることが確認できます。
ブロックスコープ
JavaScript の最新仕様 ES2015 (ES6) からブロックスコープの変数 let 、 const が利用可能となりました。
ブロックスコープは変数の影響範囲が、関数スコープよりも小さく、{} で囲まれた範囲になります。
そのため変数の影響範囲を for 文 や if 文の範囲で収めることができます。
:let を使った例
{}の中と外でそれぞれ変数 outBlock , inBlock を定義し、ブロックスコープの影響範囲を確認します。
1function func() {
2 let outBlock = "outBlockVal"
3
4 // ブロックを宣言
5 {
6 let inBlock = 'inBlockVal'
7
8 // ブロック内で変数を呼び出す
9 console.log('inside')
10 console.log('call ' + outBlock) // => call outBlockVal
11 console.log('call ' + inBlock) // => call inBlockVal
12 }
13
14 // ブロック外から変数を呼び出す
15 console.log('outside')
16 console.log('call ' + outBlock) // => call outBlockVal
17 console.log('call ' + inBlock) // => ブロック外のため呼び出せない
18}
19
20func()
【実行結果】
inside
calloutBlockVal
callinBlockVal
outside
calloutBlockVal
ReferenceError: inBlock is not defined
実行結果を見てみると、{} の内側で定義した変数は、 {} の外側で呼び出したときにエラーがでることが確認できます。
var を使った例
var で定義した変数はブロックスコープにはなりません。
そのため{}の内側で var を用いて変数を定義すると、{}の外側からでも変数にアクセスできます。
1function func() {
2 var outBlock = "outBlockVal"
3
4 // ブロックを宣言
5 {
6 var inBlock = 'inBlockVal'
7
8 // ブロック内で変数を呼び出す
9 console.log('inside')
10 console.log('call ' + outBlock) // => call outBlockVal
11 console.log('call ' + inBlock) // => call inBlockVal
12 }
13
14 // ブロック外から変数を呼び出す
15 console.log('outside')
16 console.log('call ' + outBlock) // => call outBlockVal
17 console.log('call ' + inBlock) // => call inBlockVal
18}
19
20func();
【実行結果】
inside
calloutBlockVal
callinBlockVal
outside
calloutBlockVal
callinBlockVal
JavaScript にブロックスコープはない?
JavaScript の解説記事には「ブロックスコープがない」という記述が散見されます。
しかし、先述のように JavaScript にもブロックスコープは存在します。
ただし、ブロックスコープの仕様が定められたのが、2015年のため古いブラウザでは対応していない場合があります。
let・const のブラウザの対応状況
現在のブラウザの対応状況は以下で確認できます。
ECMAScript 6 compatibility table
現在の最新ブラウザ ( Edge, Chrome, Firefox, Safari ) は標準で対応しています。(IE 11 では一部未対応)
古いブラウザまでサポートに含める場合、Babel 等のトランスパイラを利用して、ES5 のコードに変換する方法がとられます。
オススメのJavaScript入門書はこちら!
さいごに
いかがでしたでしょうか?
スコープについて理解が深まったようであれば幸いです!
こちらの記事もオススメ!
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
2020.08.07JavaScript 特集知識編JavaScriptを使ってできることをわかりやすく解説!JavaScriptの歴史【紆余曲折を経たプログラミン...
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
「好きを仕事にするエンジニア集団」の(株)ライトコードです! ライトコードは、福岡、東京、大阪の3拠点で事業展開するIT企業です。 現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。 いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。 システム開発依頼・お見積もり大歓迎! また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」「WEBディレクター」を積極採用中です! インターンや新卒採用も行っております。 以下よりご応募をお待ちしております! https://rightcode.co.jp/recruit