JavaScriptの「スコープ」について
はじめまして、かずん(@kazoonLab)と申します。
私の担当する記事では、主にJavaScript(JS)まわりの技術や、各種ツールの紹介をしていく予定です。プロフィールはこちらに載っているので、そちらをご覧ください。
本日は、JavaScriptの基本、「スコープ」について紹介していきます!
スコープとは
JavaScriptのスコープ(scope)とは、「ある変数や関数の引数を参照・更新できる範囲を示したもの」です。
スコープ内で定義された変数はスコープの中でのみ参照することができます。逆に言えば、スコープの外では参照することはできません。
JSには様々なスコープがあります。まずは、一番大きな「グローバルスコープ」の例を見てみましょう。
グローバルスコープ(global scope)
// グローバルな変数を定義 var global = 'global'; // グローバルな関数を定義 function globalFunc () { console.log('This var is ' + global); }; // 関数を呼び出す globalFunc(); // --> This var is global // 変数を更新し、関数を呼び出す global = 'grobal2'; globalFunc(); // --> This var is global2
グローバルな変数は、プログラムのあらゆる場所から値を参照・更新できます。
一見よさげに見えますが、意図せず値を書き換えてしまったりする恐れがあります。
変数がどこまで有効であるかをハッキリさせるため、JSには「関数スコープ」というものがあります。
サンプルソースを見てみましょう。
関数スコープ(functional scope)
// グローバルな関数を定義 function globalFunc () { // 関数内でローカルな変数を定義 var local = 'local'; // 関数内でローカルな関数を定義 function localFunc () { console.log('This var is ' + local); } // ローカルな関数を呼び出す localFunc(); }; // グローバルな関数を呼び出すと、ローカル関数が呼び出される globalFunc(); // --> This var is local // グローバル関数を経ず直接ローカル変数・ローカル関数を参照・実行することはできない console.log(local); // --> undefined localFunc(); // --> undefined // ローカル変数と同じ名前で変数を定義しても、ローカル変数には影響はない var local = 'not local'; console.log('This var is ' + local); // --> This var is not local globalFunc(); // --> This var is local
関数スコープを用いると、影響範囲を関数の中だけに限定した変数・関数を定義できます。
関数の外で値が更新されることはないため、プログラムの保守性がぐんとあがります。
大事なこととして、変数を宣言する際、必ず「var」をつけてください。こちらは、後ほど出てくるlet, constと合わせ、次回の記事で紹介したいと思います。
最後に、関数スコープと似て非なる「ブロックスコープ」を紹介します。
ブロックスコープ(block scope)
ブロックスコープとは、{}を書く文で作られるスコープを指します。
具体的には、if, else, for, while, switch, try, catch, ... などです。
例を見てみましょう。
// グローバルな関数を定義 function block() { // var を用いてローカル変数を宣言 var localVar = 'localVar'; // let を用いてローカル変数を宣言 let localLet = 'localLet'; if(true) { // ブロック(if文)の中でローカル変数を上書き var localVar = 'localVar2'; let localLet = 'localLet2'; console.log('if文の中ののlocalVarは' + localVar); // --> if文の中ののlocalVarはlocalVar2 console.log('if文の中ののlocalLetは' + localLet); // --> if文の中ののlocalLetはlocalLet2 } // ブロックを通った後、localVarは更新されているのに対し、 // localLetは最初に宣言したままの値が入っている console.log('if文を抜けた後のlocalVarは' + localVar); // --> if文を抜けた後のlocalVarはlocalVar2 console.log('if文を抜けた後のlocalLetは' + localLet); // --> if文を抜けた後のlocalLetはlocalLet } block();
ブロックスコープを用いることで、ブロックの中でのみ参照できる変数を作ることができます。
関数スコープよりさらに小さい感じがしますね。
なお、ブロックスコープを作る際は、変数をlet、もしくはconstで宣言する必要があります。
let、constの説明は、次回の記事でより詳細にしたいと思います。
まとめ
様々なスコープを見てきましたが、より影響範囲の小さい(バグの出にくい)変数を作るため、なるべくブロックスコープを使えると良いかと思います。当然、関数全体で使用するなら関数スコープを使わなければなりませんし、windowオブジェクトのようにそもそもグローバルな変数なものもあります。
「この変数はここでしか使わない」という小さな判断の積み重ねが、可読性の高い、整然としたソースコードにつながっていくことでしょう。
次回の記事では、接頭辞(var / let / const)の性質についてとことん語ります!
最後までご覧いただきありがとうございます。
この記事がいいなっと思ったら読者登録をお願いいたします♪