variableは変数を宣言し、任意でそれをある値に初期化します。

構文

var varname1 [= value1] [, varname2 [= value2] ... [, varnameN [= valueN]]];
varnameN
変数名。任意の有効な識別子。
valueN
変数の初期値。任意の有効な式。

説明

現れた場所に関係なく、変数の宣言はコードを実行する前に処理されます。var を伴って宣言した変数のスコープは実行コンテキスト (execution context)であり、これは変数を含んでいる関数、または関数の外で宣言された変数はグローバルになります。

宣言されていない変数への値の代入は、暗黙的にそれをグローバル変数として宣言します(グローバルオブジェクト (global object) のプロパティになります)。宣言した変数と宣言していない変数の違いは以下のとおりです:

1. 宣言した変数は、その変数を宣言した実行コンテキストの内部にあるとみなされます。宣言していない変数は、常にグローバルになります。

function x() {
  y = 1;   // strict モードでは ReferenceError をスローします。
  var z = 2;
}

x();

console.log(y); // "1" を出力します 
console.log(z); // ReferenceError をスローします。z は x の外部で定義されていません。

2. 宣言した変数は、コードを実行する前に生成されます。宣言していない変数は、変数に代入するコードを実行するまで存在しません。

console.log(a);                // ReferenceError をスローします。
console.log('still going...'); // 実行されません。
var a;
console.log(a);                // ブラウザによって "undefined" または "" を出力
console.log('still going...'); // "still going..." と出力

3. 違いは、宣言した変数は実行コンテキスト (関数またはグローバル) の設定変更不可プロパティになります。宣言していない変数は設定変更可能です (例えば、削除できます)。

var a = 1;
b = 2;

delete this.a; // strict モードでは TypeError をスローします。そうでなければ静かに失敗します。
delete this.b;

console.log(a, b); // ReferenceErrorをスローします。 
// プロパティ 'b' は削除されており、存在しません。

これら 3 つの違いにより、変数宣言に失敗し予期しない結果につながる可能性が高いです。結論として、関数スコープかグローバルスコープかにかかわらず、常に変数を宣言することをお勧めします。また、ECMAScript 5の Strict モードでは関数内で宣言していない変数に値を代入するとエラーをスローします。

varの巻き上げ(hoisting)

変数の宣言 (および一般的な宣言) はコードを実行する前に処理されますので、変数はコード内のどこで宣言しても、コードの先頭で宣言したものと等価になります。また、変数を宣言する前に変数を使用することもできます。この動作は、変数の宣言が関数やグローバルのコードの先頭に移動したように見えるため、"巻き上げ (hoisting)" と呼ばれます。

bla = 2
var bla;
// ...

// 次のように見なされます

var bla;
bla = 2;

このため、変数は常にスコープ (グローバルのコードまたは関数のコード) の先頭で宣言することをお勧めします。そうすればどの変数が関数スコープ (ローカル) であるか、あるいはスコープチェインによって決定されたものかが明確になります。

巻き上げは変数定義に影響して、値の初期化には影響しないことを理解するのも重要です。値は実際代入文に来た時に代入されます:

function do_something() {
  console.log(bar); // undefined
  var bar = 111;
  console.log(bar); // 111
}

// is implicitly understood as: 
function do_something() {
  var bar;
  console.log(bar); // undefined
  bar = 111;
  console.log(bar); // 111
}

二つの変数を宣言して初期化する

var a = 0, b = 0;

二つの変数に一つの文字列を代入する

var a = "A";
var b = a;

// 以下と等価です

var a, b = a = "A";

順番に注意してください:

var x = y, y = 'A';
console.log(x + y); // undefinedA

ここではコードを実行する前に xy が宣言され、そのあとに代入を行います。"x = y" を実行したとき、y が存在しますので ReferenceError は発生せず、値は 'undefined' になります。よって、x に undefined 値が代入されます。そして、y に値 'A' が代入されます。その結果、1 行目の後は x === undefined && y === 'A' となり、最終結果に至ります。

複数の変数を初期化する

var x = 0;

function f(){
  var x = y = 1; // x はローカルで宣言されます。y は違います!
}
f();

console.log(x, y); // 0, 1
// x は想定どおり、グローバル側の変数です。
// しかし、y は関数の外部に漏れ出ています!

暗黙のグローバル変数と関数スコープの外部

暗黙的にグローバルに現れた変数は、関数スコープの外部で参照することができます:

var x = 0;  // x はファイルスコープで宣言して、値 0 を代入

console.log(typeof z); // z はまだ存在していないため、undefined になる

function a() { // a を呼び出すと、
  var y = 2;   // y を関数 a のスコープで宣言して、値 2 を代入

  console.log(x, y);   // 0 2 

  function b() {       // b を呼び出すと、
    x = 3;  // ファイルスコープの x に 3 を代入して、新たなグローバル変数は生成しない
    y = 4;  // 外側の y に 4 を代入して、新たなグローバル変数は生成しない
    z = 5;  // 新たなグローバル変数 z を生成して、値 5 を代入 
  }         // (strict モードでは ReferenceError が発生)

  b();     // b を呼び出すと、グローバル変数として z を生成
  console.log(x, y, z);  // 3 4 5
}

a();                   // b も呼び出す
console.log(x, z);     // 3 5
console.log(typeof y); // y は関数 a のローカル変数であるため、undefined になる

仕様

仕様書 策定状況 コメント
ECMAScript 1st Edition (ECMA-262) 標準 最初期の定義。JavaScript 1.0 で実装。
ECMAScript 5.1 (ECMA-262)
var statement の定義
標準  
ECMAScript 2015 (6th Edition, ECMA-262)
variable statement の定義
標準  
ECMAScript Latest Draft (ECMA-262)
variable statement の定義
ドラフト  

ブラウザ実装状況

機能ChromeEdgeFirefoxInternet ExplorerOperaSafari
基本サポート 有り 有り1 有り 有り 有り
機能Android webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
基本サポート 有り 有り 有り4 有り 有り ?

参照

ドキュメントのタグと貢献者

タグ: 
 このページの貢献者: Uemmra3, yy_y_ja_jp, yyss, teoli, ledsun, ethertank, Potappo, Mgjbot, Nanto vi
 最終更新者: Uemmra3,