• トップ
  • ブログ一覧
  • 【JavaScript】スコープを意識して保守性の高いコードを作ろう!
  • 【JavaScript】スコープを意識して保守性の高いコードを作ろう!

    広告メディア事業部広告メディア事業部
    2019.05.10

    エンジニアになろう!

    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!
    ミツオカミツオカ
    ちなみに、スコープを意識する必要性は?

    にゃんこ師匠 にゃんこ師匠
    スコープを意識する…つまりは変数や関数の有効範囲を意識すること、影響範囲を意識することだにゃ

    ミツオカミツオカ
    変数の影響範囲を必要最低限に抑えることで、保守性の高いプログラムになるということですね

    にゃんこ師匠 にゃんこ師匠
    うむ!ちなみにスコープの種類としては3つあるので覚えておくのだ
    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入門書はこちら!

    確かな力が身につくJavaScript「超」入門

    さいごに

    いかがでしたでしょうか?

    スコープについて理解が深まったようであれば幸いです!

    こちらの記事もオススメ!

    featureImg2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
    featureImg2020.08.07JavaScript 特集知識編JavaScriptを使ってできることをわかりやすく解説!JavaScriptの歴史【紆余曲折を経たプログラミン...

    にゃんこ師匠 にゃんこ師匠
    ミツオカ、今回の記事をまとめるのだ!

    ミツオカミツオカ
    1. JavaScript には変数の影響範囲をきめるスコープがある
    2. グローバルスコープの変数、関数の影響範囲は、プログラム全体に及び、どこからでもアクセスできる
    3. ローカルスコープ(関数内で定義した)変数、関数の影響範囲は、関数内に留まる
    4. ブロックスコープ(let, const で定義した変数、関数)の影響範囲は、{} に囲まれた範囲に留まる
    にゃんこ師匠 にゃんこ師匠
    スコープを意識することで、変数の有効範囲を限定でき、バグが少なく保守性の高いコードを作成することができるのだ

    ミツオカミツオカ
    スコープを意識したプログラム作りの大事さが分かりました~!
    広告メディア事業部

    広告メディア事業部

    おすすめ記事