• トップ
  • ブログ一覧
  • 【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 で定義した変数、関数)の影響範囲は、{} に囲まれた範囲に留まる
    にゃんこ師匠 にゃんこ師匠
    スコープを意識することで、変数の有効範囲を限定でき、バグが少なく保守性の高いコードを作成することができるのだ

    ミツオカミツオカ
    スコープを意識したプログラム作りの大事さが分かりました~!

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    広告メディア事業部

    広告メディア事業部

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background