「JavaScript/変数」の版間の差分
削除された内容 追加された内容
タグ: モバイル編集 モバイルウェブ編集 |
クリーンアップ |
||
1 行
{{Nav}}
変数 ({{lang-en-short|variable}}) は、
== 変数の宣言
「変数」は、オブジェクトに名前をつけて参照の手助けをする機能です。
型や値は変数ではなくオブジェクトとプリミティブが保持しています<ref>オブジェクトとプリミティブをあわせてインスタンスということがあります。</ref>。
静的な言語に慣れた人は、やや戸惑いを感じるかもしれません。
JavaScriptで変数を宣言する方法は、一般的には<code>var</code>, <code>let</code> または
== var ==
JavaScript の変数はES2015より前は <code>var</code> しか存在しませんでした。
'''コード例'''
<syntaxhighlight lang="javascript">
var x = 2;
x = "abc";
console.log(x + 3); // x + 3 を評価した結果の abc3 を表示
</syntaxhighlight>
=== 未宣言のグローバル変数 ===
宣言を行う前に変数に代入することはできます。
<syntaxhighlight lang="javascript">
x = 2;
</syntaxhighlight>
宣言を行っていない変数に値を代入することも可能で'''未宣言のグローバル変数'''を生成します。
ただし、未宣言のグローバル変数の生成は[[JavaScript/strictモード|strictモード]]では SyntaxError になることからも判る通り'''非推奨'''です。
未宣言のグローバル変数の挙動は予測困難で難解なバグの原因になりえます。
このため、未宣言のグローバル変数はつくらないよう必ず <code>var</code>, {{code|let}} または {{code|const}} で宣言しましょう。
{{See also|[[JavaScript/関数|varの巻上げ]]}}
<syntaxhighlight lang="javascript">
var x;
y = 100; // 未宣言変数への代入
z = 200; // グローバル変数への代入の実体は、グローバルオブジェクトのプロパティへの代入
window.z = 200; // これとおなじ
</syntaxhighlight>
既に var または let で作成された変数の値を書き換えるのならキーワード無しでも可能ですが、その場合は宣言ではなく代入になります。
<syntaxhighlight lang="javascript">
var x = 8;
x = "abc"; // 違う型のオブジェクトを代入
</syntaxhighlight>
代入をする時、それまでの値の型と違う型であっても構いません。
JavaScriptは動的な言語なので「変数はオブジェクトに名前を提供し参照の手助け」をしていることを端的に表しています。
== 変数名 ==
215 ⟶ 76行目:
Unicodeの文字の中に「いわゆる全角スペース」は含まれません。
== let ==
<code>var</code> キーワードは関数スコープを持つのに <code>if</code>文や<code>for</code>文などのスコープを持たないので不便な場合があったりJavaScriptに馴れないプログラマに混乱を引きおこす場合がありました。
ECMA2015から新たに導入された<code>let</code>キーワードで宣言された変数はブロックスコープをもちます。<code>{ }</code>の中がブロックで、ブロックを出ると<code>let</code>で宣言した変数は参照できなくなります。
for文中の式は単文で<code>{ }</code> は使われていない場合も<code>for</code>文のスコープを持つと解釈されます。
つまり、<code>for</code>文の条件式でも<code>let</code>で宣言された変数は<code>for</code>文を出ると参照できなくなります。
<syntaxhighlight lang="JavaScript">
'use strict';
for (let i = 0; i < 10; i++) // 波括弧{}でなくてもfor文はブロックスコープ
console.log(i);
console.log(i); // ReferenceError: i is not defined
</syntaxhighlight>
{{code|let}} は、ひとつのスコープ内での再宣言は出来ません。
<syntaxhighlight lang="javascript" line>
// 二行目でエラーになります
let x = 1; // これは代入ではなく初期化を伴うlet変数宣言
let x = 2; // 再宣言してるので SyntaxError: ここでスクリプトは中止
// x + 3 を計算
console.log(x + 3); // 既にエラーなので「5」は表示されない
</syntaxhighlight>
<code>let</code> 宣言された変数のインスタンスとの束縛を変えるには、<code>let</code>変数宣言ではなく代入を行います。
[[JavaScript/strictモード|strict モード]]でも代入が可能です。
つまり、下記のコードは表示が可能です。
<syntaxhighlight lang="javascript">
'use strict';
let x = 1; // 初期化を伴う let 変数宣言
x = 2; // 代入
// x + 3 を計算
console.log(x + 3); // 5 を表示
</syntaxhighlight>
当然、(strictモードではない)通常モードでも代入が可能です。
<syntaxhighlight lang="javascript">
// このコードは可能
let x = 1;
x = 2; // 代入
// x + 3 を計算
console.log(x + 3); // 5 を表示
</syntaxhighlight>
== const ==
<code>const</code>キーワードで変数を宣言すると、その値は初期化の時以外は書き換えられず「定数」(ていすう)として振る舞います。
<syntaxhighlight lang="javascript">
const E; // SyntaxError: Missing initializer in const declaration
</syntaxhighlight>
<code>const</code> で宣言された変数(定数)のスコープは <code>let</code> で宣言された変数と同じ'''ブロックスコープ'''を取ります。
定数はスコープの全域で使われる不変な値に対して用いられ
<syntaxhighlight lang="javascript">
237 ⟶ 143行目:
</syntaxhighlight>
'''const の定数的でない例'''
<syntaxhighlight lang="javascript">
const obj = { a: 1, b: 2};
for (const prop in obj)
console.log(prop);
/*
a
b
*/
</syntaxhighlight>
の様に、一度だけしか代入されない変数や for-in文 や for-of文 のループ変数も const で宣言することができ、値がブロックのかなで不変であったり左辺値化ができないことを明示することができます。「定数」と
constと宣言された定数への代入は SyntaxError を throw します。
246 ⟶ 163行目:
</syntaxhighlight>
<code>const</code> は定数を宣言しますが、Arrayオブジェクトや Objectオブジェクトのような複合的なオブジェクト(コレクション)の要素の変更は妨げません。<!--混乱するのでObject.seal() メソッドやObject.freeze()メソッドには触れなかった。-->
<syntaxhighlight lang="javascript" line>
const ary1 = [1,2,3];
257 ⟶ 174行目:
# 定数な筈のaryの要素を書き換え(ary1を初期化したインスタンスの要素の書き換え)。
# 書き換えたのは ary2 の1番めの要素なのに、ary1の要素が書き換わっている。これは、2行目でary2をary1で初期化しているためで、この時 ary2 は ary1 の別名になっています。
{{コラム|JavaScriptにおける「定数」とは値の変更を許さない変数のこと|
「定数」を「変数」の特殊なものに分類するのは、数学的には違和感を感じる人もいるかもしれないがプログラミングでは便宜上このように分類します。
プログラミングでいう「変数」とは、データに値を名前をつけるものという意味で、数学でいう値の変動する代数とはプログラミング「変数」は意味が異なることに気をつけて下さい。
}}
== 変数のスコープ ==
変数が参照可能な範囲を変数の'''スコープ'''といいます。
=== 関数スコープ ===
<code>var</code>で宣言された変数はその関数外では参照ができなくなります。
この様なスコープを'''関数スコープ'''といいます。
281 ⟶ 204行目:
上記の''x''は関数の中と外では異なる変数になるので、外側の''x''の値は冒頭の<code>var x = 1;</code>のままです。
一方で、下記コードの''x''はブロックの中と外で同じ変数を指すので
<syntaxhighlight lang="JavaScript">
293 ⟶ 216行目:
</syntaxhighlight>
なので実行結果は
2 2 です。 これは次のような場合に問題となります。
1 秒間隔で 0, 1, 2 と出力するプログラムを書く場合、下記のようにコードを書いても、「333」となってしまい、失敗します。
<!-- 最後まで「1 秒間隔で 0, 1, 2 と出力するプログラム」にはなっていないと思う。Promise での実装を最後に書くべき? --> <syntaxhighlight lang="JavaScript">
305 ⟶ 232行目:
}, 1000);
}
</syntaxhighlight>
'''結果'''は
3
3
3
となり、
0
1
2
にはなりません。
また、1秒ほど経過した後3行同時に表示する動きになります。
=== ブロックスコープ ===
2020年現在なら、この問題は<code>let</code>キーワードで容易に解決できます。ECMA2015で<code>let</code>キーワードが導入されました。
<code>{ }</code>の中がブロックで、ブロックの中で<code>let</code>で宣言した変数はブロックを出ると参照できなくなります。
この様なスコープのことを'''ブロックスコープ'''と呼びます。
<syntaxhighlight lang="JavaScript">
321 ⟶ 257行目:
setTimeout(() => console.log(i), 1000);
}
</syntaxhighlight>
'''結果'''
0
1
2
なお、ECMAScript 5以前はlet宣言は無かったので、上述の問題を解決するには次のように即時関数(関数を定義すると同時に実行するためのイデオム)を使って関数スコープを作るしかありませんでした。
335 ⟶ 274行目:
</syntaxhighlight>
== varの巻き上げ ==
<code>var</code> で宣言した変数は、未宣言で代入したあと改めて宣言すると、スコープの先頭にさかのぼって宣言されていたと仮定する(そのため宣言どころか代入前の参照が ReferenceError にならない)と言う挙動を示します。
{{See also|[[JavaScript/関数|varの巻上げ]]}}
{{コラム|console画面の開き方と使い方|
# ウェブブラウザを開く。
359 ⟶ 284行目:
# 画面下部などに出てきたウィンドウのタブ欄にあるconsoleタブをクリックして、console入力に切り替える。
# そこにコンソール用のコードを貼り付ける。
}}
== 脚注 ==
421 ⟶ 291行目:
== 参考文献 ==
* [https://mathiasbynens.be/notes/javascript-identifiers Valid JavaScript variable names in ECMAScript 5 - Mathias Bynens]
* [https://mathiasbynens.be/notes/es6-const ES6 const is not about immutability - Mathias Bynens]
[[Category:JavaScript|へんすう]]
|