「JavaScript/変数」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
→‎関数スコープ: let との比較
Ef3 (トーク | 投稿記録)
varよりconstとletを先にした。
1 行
{{Nav}}
変数 ({{lang-en-short|variable}}) は、オブジェクトやプリミティブに名前をつけ、名前で参照を可能にする機能です。
 
== 変数の宣言 ==
7 行
静的な言語に慣れた人は、やや戸惑いを感じるかもしれません。
 
JavaScriptで変数を宣言する方法は、一般的には <code>varlet</code>, <code>letconst</code> または <code>constvar</code> キーワードで宣言します。
 
== var ==
JavaScript の変数はES2015より前は <code>var</code> しか存在しませんでした。
'''コード例'''
<syntaxhighlight lang="javascript">
var x = 2;
console.log(x + 3); // x + 3 を評価した結果の 5 を表示
x = "abc";
console.log(x + 3); // x + 3 を評価した結果の abc3 を表示
</syntaxhighlight>
 
=== 未宣言のグローバル変数 ===
宣言を行う前に変数に代入することはできます。
<syntaxhighlight lang="javascript">
x = 2;
console.log(x + 3); // x + 3 を評価した結果の 5 を表示
</syntaxhighlight>
宣言を行っていない変数に値を代入することも可能で'''未宣言のグローバル変数'''を生成します。
 
ただし、未宣言のグローバル変数の生成は[[JavaScript/strictモード|strictモード]]では SyntaxError になることからも判る通り'''非推奨'''です。
未宣言のグローバル変数の挙動は予測困難で難解なバグの原因になりえます。
このため、未宣言のグローバル変数はつくらないよう必ず <code>var</code>, {{code|let}} または {{code|const}} で宣言しましょう。
{{See also|[[JavaScript/関数|varの巻上げ]]}}
 
<syntaxhighlight lang="javascript">
var x;
console.log(x); // undefined を表示(ReferenceErrorになるのは未宣言の場合で、この場合はならない)
y = 100; // 未宣言変数への代入
console.log(y); // 100 を表示、結果的に代入が宣言のように振る舞う。
z = 200; // グローバル変数への代入の実体は、グローバルオブジェクトのプロパティへの代入
window.z = 200; // これとおなじ
</syntaxhighlight>
 
既に var または let で作成された変数の値を書き換えるのならキーワード無しでも可能ですが、その場合は宣言ではなく代入になります。
<syntaxhighlight lang="javascript">
var x = 8;
console.log(x); // 8 を表示
x = "abc"; // 違う型のオブジェクトを代入
console.log(x); // abc を表示
</syntaxhighlight>
代入をする時、それまでの値の型と違う型であっても構いません。
JavaScriptは動的な言語なので「変数はオブジェクトに名前を提供し参照の手助け」をしていることを端的に表しています。
 
== 変数名 ==
JavaScriptの変数名は、関数・プロパティ・ラベルなどとおなじく識別子(しきべつし;Identifier)の規約に従います。
JavaScriptの識別子は、Unicode の文字、$、_、数字(0-9)からなります。識別子は大文字小文字を区別します。
識別子は数字(0-9)からはじまってはいけません。
また予約語(よやくご;keyword)を識別子に使うことは出来ません。
変数名は関数名との重複は許されませんがラベル名との重複は許されます。
 
<syntaxhighlight lang="JavaScript">
var primeNumber = 57; // OK
var prime_number = 57; // OK
var prime-number = 57; // SyntaxError、ハイフンは変数名に使えない
</syntaxhighlight>
 
変数名には[[Java]]と同様、慣習的に<source lang="javascript" inline>var variableNamesLikeThis</source>のような[[:w:キャメルケース|キャメルケース]]が用いられます。
外部に公開しない変数はあえて短めにし、一時的な変数であることを伝えようとする傾向がありますが、コーディング規約で定めていない限りリラックスした名付けが行われます。
ただし日本語の単語をローマ字表記した変数名は単数複数の区別がないので <source lang="javascript" inline>for (let item in items)</source>の様な名付けが行えなかったり、'''月'''のつもりで '''tuki''' と綴ったら ReferenceError: '''tsuki''' is not defined と翻字のゆらぎでミスタイプとなる可能性を増やすので推奨しません(この例ではtukiがmoonなのかmonthなのかにも曖昧さが生じ、いっそ <source lang="javascript" inline>var 月</source> の方が良いのかもとさえ思えます)。
 
Unicodeの文字が有効なので
<syntaxhighlight lang="JavaScript">
var π = 4 * Math.atan(1);
</syntaxhighlight>
は正しいプログラムです。
 
Unicodeの文字の中に「いわゆる全角スペース」は含まれません。
 
== let ==
<code>varlet</code> キーワードは関で宣言された変はブロックスコープを持つのに もちます。<code>if{ }</code>文やの中がブロックで、ブロックを出ると<code>forlet</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>文のブロックスコープ出ると参照できなくなり持ちます。
<code>for</code>文の条件式でも<code>let</code>で宣言された変数は<code>for</code>文を出ると参照できなくなります。
 
<syntaxhighlight lang="JavaScript">
128 ⟶ 58行目:
 
== const ==
<code>const</code>キーワードで変数を宣言すると、その値は初期化の時以外は書き換えられず「定数」(ていすう)として振る舞います。
<syntaxhighlight lang="javascript">
const E; // SyntaxError: Missing initializer in const declaration
180 ⟶ 110行目:
プログラミングでいう「変数」とは、データに値を名前をつけるものという意味で、数学でいう値の変動する代数とはプログラミング「変数」は意味が異なることに気をつけて下さい。
}}
 
== 変数名 ==
JavaScriptの変数名は、関数・プロパティ・ラベルなどとおなじく識別子(しきべつし;Identifier)の規約に従います。
JavaScriptの識別子は、Unicode の文字、$、_、数字(0-9)からなります。識別子は大文字小文字を区別します。
識別子は数字(0-9)からはじまってはいけません。
また予約語(よやくご;keyword)を識別子に使うことは出来ません。
変数名は関数名との重複は許されませんがラベル名との重複は許されます。
 
<syntaxhighlight lang="JavaScript">
const primeNumber = 57; // OK
const prime_number = 57; // OK
const prime-number = 57; // SyntaxError、ハイフンは変数名に使えない
</syntaxhighlight>
 
変数名には[[Java]]と同様、慣習的に<source lang="javascript" inline>var variableNamesLikeThis</source>のような[[:w:キャメルケース|キャメルケース]]が用いられます。
外部に公開しない変数はあえて短めにし、一時的な変数であることを伝えようとする傾向がありますが、コーディング規約で定めていない限りリラックスした名付けが行われます。
ただし日本語の単語をローマ字表記した変数名は単数複数の区別がないので <source lang="javascript" inline>for (let item in items)</source>の様な名付けが行えなかったり、'''月'''のつもりで '''tuki''' と綴ったら ReferenceError: '''tsuki''' is not defined と翻字のゆらぎでミスタイプとなる可能性を増やすので推奨しません(この例ではtukiがmoonなのかmonthなのかにも曖昧さが生じ、いっそ <source lang="javascript" inline>var 月</source> の方が良いのかもとさえ思えます)。
 
Unicodeの文字が有効なので
<syntaxhighlight lang="JavaScript">
var π = 4 * Math.atan(1);
</syntaxhighlight>
は正しいプログラムです。
 
Unicodeの文字の中に「いわゆる全角スペース」は含まれません。
 
== var ==
JavaScript の変数はES2015より前は <code>var</code> しか存在しませんでした。
var で宣言した変数は、後述する巻き上げなどのややトリッキーな挙動を示すのでES2015で const と let が導入されました。
特別な理由があるとき以外は、 const あるいは let で宣言してください。
 
'''var を使ったコード例'''
<syntaxhighlight lang="javascript">
var x = 2;
console.log(x + 3); // x + 3 を評価した結果の 5 を表示
x = "abc";
console.log(x + 3); // x + 3 を評価した結果の abc3 を表示
</syntaxhighlight>
 
=== 未宣言のグローバル変数 ===
宣言を行う前に変数に代入することはできます。
<syntaxhighlight lang="javascript">
x = 2;
console.log(x + 3); // x + 3 を評価した結果の 5 を表示
</syntaxhighlight>
宣言を行っていない変数に値を代入することも可能で'''未宣言のグローバル変数'''を生成します。
 
ただし、未宣言のグローバル変数の生成は[[JavaScript/strictモード|strictモード]]では SyntaxError になることからも判る通り'''非推奨'''です。
未宣言のグローバル変数の挙動は予測困難で難解なバグの原因になりえます。
このため、未宣言のグローバル変数はつくらないよう必ず {{code|const}}, {{code|let}} または <code>var</code> で宣言しましょう。
{{See also|[[JavaScript/関数|varの巻上げ]]}}
 
<syntaxhighlight lang="javascript">
var x;
console.log(x); // undefined を表示(ReferenceErrorになるのは未宣言の場合で、この場合はならない)
y = 100; // 未宣言変数への代入
console.log(y); // 100 を表示、結果的に代入が宣言のように振る舞う。
z = 200; // グローバル変数への代入の実体は、グローバルオブジェクトのプロパティへの代入
window.z = 200; // これとおなじ
</syntaxhighlight>
 
既に var または let で作成された変数の値を書き換えるのならキーワード無しでも可能ですが、その場合は宣言ではなく代入になります。
<syntaxhighlight lang="javascript">
var x = 8;
console.log(x); // 8 を表示
x = "abc"; // 違う型のオブジェクトを代入
console.log(x); // abc を表示
</syntaxhighlight>
代入をする時、それまでの値の型と違う型であっても構いません。
JavaScriptは動的な言語なので「変数はオブジェクトに名前を提供し参照の手助け」をしていることを端的に表しています。
 
== 変数のスコープ ==
203 行
a
1
です。
です。プログラムは上から実行するので、上記コードの場合は結果的に最初に{}ブロック内の <code> console.log(x); // a </code>が実行され、次に{}ブロック外の<code> console.log(x); // 1 </code>が実行されるからです。
上記の''x''は関数の中と外では異なる変数になるので、外側の''x''の値は冒頭の<code>var x = 1;</code>のままです。
 
一方で、下コードの''x''はブロック関数の中と外で同じ変数を指すので(<code>var</code>で宣言された変数関数スコープを持ちますが<code>if</code>文のブロックのかも同じ関る変ので外側の''x''の値が変わってしは冒頭の<code>var x = 1;</code>のす。
 
<code>var</code>で宣言された変数は関数スコープを持ちますが<code>if</code>文のブロックのなかも同じ関数なので、下記コードの''x''はブロックの中と外で同じ変数を指すので、''x''の値が変わります。
<syntaxhighlight lang="JavaScript">
var x = 1;
263 行
 
=== ブロックスコープ ===
2020年現在なら、この問題はECMA2015で<code>letconst</code>キーワードで容易に解決できます。ECMA2015で<code>let</code>キーワードが導入されました。
<code>{ }</code>の中がブロックで、ブロックの中で<code>let</code>で宣言した変数はブロックを出ると参照できなくなります。
この様なスコープのことを'''ブロックスコープ'''と呼びます。
271 行
 
// for の次が var i = 0 でなく let i = 0 に変わっている
for (let i = 0; i < 3; i++) { // ECMA2015ES2015なのでアロー関数によるラムダ式を使った
setTimeout(() => console.log(i), 1000);
}
290 行
})(i);
</syntaxhighlight>
 
 
== varの巻き上げ ==
302 ⟶ 301行目:
# そこにコンソール用のコードを貼り付ける。
}}
 
 
== 脚注 ==