変数 (variable)

宣言 (declaration)

var varname1 [= value1] [, varname2 [= value2] ... [, varnameN [= valueN]]];
Syntax - var - JavaScript | MDN
var a = 1, b = 2;

同一の値で初期化するならば、

var a = 1, b = 1;

次のようにも記述できます。

var a, b = a = 1;
Examples - var - JavaScript | MDN

未宣言 (undeclared)

未宣言の判定

オブジェクトのプロパティならば、in演算子でその存在を確認できます。またグローバル変数でも、それがWindowオブジェクトのプロパティとなることを利用して、同様に

'a' in window;

とすることで宣言を確認できます。なお、このとき変数名は文字列で指定することに注意します。

グローバル変数 (global variable)

関数内var文を使用して宣言する以外、すべてグローバル変数となります。関数外で使用する変数がグローバル変数となることを避けるには、匿名関数の中で変数を宣言します。

var a = 0;  // グローバル変数
b = 0;      // グローバル変数

function Foo()
{
    var c = 0;  // ローカル変数
    d = 0;      // グローバル変数
}

ローカルかグローバルかを明確にするために、変数の宣言では必ずvar文を使用します。

とろこでクライアントサイドJavaScriptならば、var文を用いず宣言されたグローバル変数はWindowオブジェクトのプロパティとなります。

巻き上げ (hoisting) / ホイスティング

var文で変数を宣言すると、その宣言より先に変数が参照された場合でも、先に宣言されているものと解釈されます。これを「varの巻き上げ」と呼びます。varの巻き上げ(hoisting) - var - JavaScript | MDN

var 先に宣言 後で宣言
あり
{
  var a = 1;
  alert( a ); // 1
}
問題なし
{
  alert( a ); // undefined
  var a = 1;
}
宣言より先に参照しているが、未定義値、つまり宣言はされているが初期化されていないと解釈されている。
なし
{
  a = 1;
  alert( a ); // 1
}
問題なし
{
  alert( a ); // ReferenceError: a is not defined
  a = 1;
}
varを付けずに宣言して、その宣言より先に参照すると、ReferenceError、つまり宣言されていないと解釈されている。

このように宣言前に参照すると特殊な挙動を示すため、つねに先に宣言するようにします。

定義 (definition)

未定義 (undefined)

変数の宣言時に初期化されないとき、値が設定されるまでは未定義の状態となります。

var a;     // 初期化していない
var b = 0; // 初期化している

a = 0; // ここまで未定義 (undefined)

未定義の判定

未定義値は、

typeof a === 'undefined'

のようにtypeof演算子の戻り値で判定できます。次のような判定方法もあるようですが、これらの方法では宣言すらされていないと例外が発生します。

  • a === undefined
  • a === void 0
  • !a
  • a == null
JavaScript:undefined値の判定 - 泥のように

一方でオブジェクトのプロパティが定義されているかどうかは、in演算子で判定できます。

未宣言と未定義の変数からの、読み込みと代入

変数の状態 操作 結果
宣言 代入
宣言されていない
(未宣言)
値が設定されていない 読み込み 例外が発生

(ReferenceError: x is not defined)

代入 グローバルな変数の宣言となる
宣言されている 値が設定されていない
(未定義)
読み込み 未定義 (undefined) が返される
値が設定されている 代入 問題なく代入される

たとえば次のようになります。

x = y; // ReferenceError: y is not defined

var a;
var b = 1; // b==1となる (関数内ならば、ローカル スコープ)
c = 1;     // c==1となる (グローバル スコープ)

x = a; // undefined
x = b; // x==1となる

一方でオブジェクトのプロパティの場合は、次のようになります。

var obj = { a: 1 };

x = obj.a;   // x==1となる
x = obj.b;   // undefined

x = obj.a.b; // undefined
x = obj.b.b; // TypeError: obj.b is undefined

obj.b = 1;   // obj.b==1となる
TypeError - JavaScript | MDN

変数のスコープ

種類 スコープの範囲
グローバル変数 プログラム全体
ローカル変数 変数が宣言された関数の中だけ
関数の仮引数 その関数の中だけ

ブロック内の変数

関数内で宣言された変数は、どのブロックで宣言されたかにかかわらず関数全体で有効となります。

function Foo( x )
{
    if( x )
    {
        var a = 256;
    }

    for( var b = 0; b < 10; b++ )
    {
    }

    alert( a ); // aは有効だが、xの値によってはundefinedの場合もある
    alert( b ); // bは有効で、つねに10
}

JavaScriptには、ブロックレベルのスコープはありません。ただしlet演算子を使える環境ならば、ブロックレベルのスコープを実現できます。

let演算子

スコープをブロックレベルに制限して、変数を宣言できます。

<script type="application/javascript;version=1.7">
    {
        var a = 1;
        let b = 1;
    }

    alert( a ); // 1
    alert( b ); // ReferenceError: b is not defined

</script>
let - JavaScript | MDN

let演算子はJavaScript 1.7以降でサポートされるため、HTML文書中のscript要素では

<script type="application/javascript;version=1.7">

のように、1.7以降のバージョンを明示する必要があります。さもなくばSyntaxErrorとなります。一方でXULではこのような配慮は不要です。Summary - let - JavaScript | MDN

そもそもletをサポートしないブラウザではこのようなバージョンの記述は無意味で、そのようなブラウザを対象とするならばletの使用を断念します。Browser compatibility - let - JavaScript | MDN

宣言と実行のタイミング

関数内で宣言された変数は、その関数全体で有効であるという定義のために、宣言する場所にかかわらず有効です。しかし初期化されるのは、それが実行された場所になります。

function Foo()
{
    var a = 1;

    alert( a ); // aは有効で、1を出力
    alert( b ); // bは有効だが、undefinedを出力
    alert( c ); // cは無効で、例外が発生

    var b = 1;
}

宣言する前に実行されることがないように、変数は関数の先頭で宣言するようにします。

alert( a ); // 初期化前: undefined と表示
var a = 1;
alert( a ); // 初期化後: 1 と表示

alert( b ); // 初期化前 (varなしで宣言): エラー発生 (ReferenceError: b is not defined)
b = 1;

定数 (Constants)

constキーワードを使用することで、定数を宣言することができます。定数 - Values, variables, and literals - JavaScript | MDN

const PI = 3.14;

※ Internet Explorer 11より前は、constキーワードに対応していません。Browser compatibility - const - JavaScript | MDN

constで宣言した定数に新たな値を上書きしようとしても、その値は無視されます。

const a = 1;
a = 2;

alert( a ); // 1と表示

また同名の変数を宣言して上書きしようとすると、例外が発生します。

const a = 1;
const a = 2; // TypeError: redeclaration of const a