JavaScript/変数

出典: フリー教科書『ウィキブックス(Wikibooks)』
ナビゲーションに移動 検索に移動

変数は、データに名前をつけることができる機能です。

JavaScriptの変数はvarキーワードで宣言します。

// x の 2 乗を計算

var x = 2;

console.log(x * x);

これにより、もし3の2乗を計算したくなっても、1か所を変えるだけで済むようになります。

変数を使わず、単に

console.log(2 * 2);

とした場合は、2か所を変えなければなりません。

データにxという別名を与えることで、ある種の抽象化が行えるようになるわけです。同じデータを100か所で使う必要があったとしたら、変数の重要性は増大するでしょう。

JavaScriptの変数は型をもたないので、数値でも文字列でも(関数でも)、なんでも代入することができます。

var five = '5';
var one = 1;

console.log(five + one); // 文字列の「5」と数値の1を合わせ51

次のように複数の変数をまとめて宣言することもできます。

var five = '5', one = 1; // 文字列の「5」と数値の1を宣言する

ただし、これは他人から見ると予想外に見づらいので、1行に1つにすることを推奨します。もっともこれは面倒なvarキーワードを省けるという意味はあります。

次のように宣言と代入を分けることは無意味で回りくどいのでしてはいけません(条件によって異なる値を代入したい場合などは除きます)。

var five;
five = '5';

また、宣言後また同じ変数で違う値を宣言すると変数は書き換えられます。

var five = '5';
five = '50';

宣言しただけで値を代入していない変数には、未定義であることを表すundefinedが入っています。

var five;
console.log(five); // undefined

宣言も代入もされていない変数を参照しようとするとエラーになります。これは変数名をタイプミスした場合によく生じます。

console.log(fibe); // ReferenceError: fibe is not defined

プログラムのトップレベル(プログラムの先頭など関数の内側ではない一番外側)で宣言された変数は、プログラムのどこからでもアクセスできるグローバル変数になります。また、varキーワードで宣言せずに変数に値を代入すると、トップレベル以外でもグローバル変数を定義することができます。'use strict;'はこのような明示的に宣言されていないグローバル変数の定義を禁止します。

'use strict';

a = 3; // ReferenceError: assignment to undeclared variable a

変数名[編集]

JavaScriptの変数名には英数字、半角カナ、アンダースコア(_)、ドル記号($)が使用できます。大文字・小文字は区別されます。

  • 0123456789
  • ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • abcdefghijklmnopqrstuvwxyz
  • アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン
  • _
  • $

多くの言語と同様、変数名の先頭に数字を用いることはできません(これは0xbadのような数値との混同を防ぐためと考えられます)。ハイフン(-)は使えないことに注意してください。また、classなどのキーワードも変数名に用いることはできません。

var primeNumber = 57; // OK
var prime_number = 57; // OK
var prime-number = 57; // SyntaxError

変数名にはJavaと同様、慣習的にvar variableNamesLikeThisのようなキャメルケースが用いられます。どうでもいい変数はvar stringよりかはvar str、あるいはvar sのように、気楽に略語が用いられます(外部に公開するメソッド名には略語はあまり用いられません)。

var hogeのようなローマ字の変数名は非日本語話者にとって意味不明になるため、グローバル化の時代にあっては推奨されません。文法は適当でもいいので、変数名は必ずvar fooのように英語でつけるようにしましょう。

JavaScript 1.5からは日本語を含むUnicode文字、および\uXXXX形式のUnicodeエスケープシーケンスも変数名に使えるようになりました。これらは主にハックに用いられます。

var π = 4 * Math.atan(1);

定数[編集]

定数はconstキーワードで宣言します。宣言と同時に代入しなければならず、値は変更できません。定数はプログラムの全域で使われるような不変なデータに対して用いられ、プログラムの冒頭で宣言されるのが典型的な使われ方です。

'use strict';

const E = 3;

console.log(E); // 3

E = 2.7; // SyntaxError: invalid assignment to const E

定数名は全大文字で、const CONSTANT_VALUES_LIKE_THISのようにスネークケースで書く慣習があります。

変数のスコープ[編集]

変数が使える範囲のことを変数のスコープといいます。JavaScriptでは、varで宣言された変数は関数スコープをもち、if文やfor文などのブロックはスコープを作りません。

var x = 1;

(function() {
  var x = 2;

  console.log(x); // 2
})();

console.log(x); // 1

上記のxは関数の中と外では違う変数になるので、外側のxの値は変わりません。一方で、下記のxはブロックの中と外で同じ変数を指すので、xの値が変わってしまいます。

var x = 1;

if (x === 1) {
  var x = 2;

  console.log(x); // 2
}

console.log(x); // 2

これは次のような場合に問題となります。

// 1 秒間隔で 0, 1, 2 と出力

for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}

// -- するはずが実際に出力されるのは 3, 3, 3

この問題を解決するには、ECMAScript 5以前は次のように無理やり関数スコープを作るしかありませんでした。

for (var i = 0; i < 3; i++) (function(i) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
})(i);

varの巻き上げ[編集]

加えてvarで宣言された変数に関しては、値の代入は代入した場所で行われるが、宣言はどこでしても関数の先頭でしたことになるという落とし穴が存在します。この挙動はvarの巻き上げ(var hoisting)と呼ばれます。

(function() {
  console.log(dream); // undefined -- なぜかReferenceErrorにならない

  var dream = true;
  console.log(dream); // true
})();

なぜ宣言する前にdreamを参照している(ように見える)のにエラーにならないかというと、これは次のように解釈されるからです。

(function() {
  var dream; // ファッ!?

  console.log(dream); // undefined

  dream = true;
  console.log(dream); // true
})();

これに巻き込まれないよう、宣言する前に変数を使わないように注意しましょう。

varにはこういった問題があるのですが、かといって「常に関数の先頭で全部の変数を宣言するようにし、途中でvarを使わないようにする」というのでは、昔のCみたいで、あまりに退屈です。ハッカーは問題を解くのに適した言語を作るべきで、言語に人間が合わせるべきではありません。そもそもの問題はvarがブロックスコープをもたないことにあるのだから、ブロックスコープをもつvarを発明するのが筋です。

let[編集]

letキーワードで宣言された変数はブロックスコープをもちます。さらにfor文の条件式でletで宣言された変数は、for文のブロックの内側にしか見えません。

'use strict';

for (let i = 0; i < 10; i++) {
  console.log(i);
}

console.log(i); // ReferenceError: i is not defined

ただしFirefox 39までの実装にはバグがあり、forの条件式でletで宣言された変数がforの外に見えてしまっていました[1]Gnuzilla Icecatの最新版はいまだに38ですので注意してください。

脚注[編集]

  1. ^ Bug 854037 - fresh binding per iteration of C-style for-let

参考文献[編集]