第2章:JavaScript入門:値、変数、制御フロー
¶ コンピュータの世界では、データしか存在しません。データでないものは存在しません。すべてのデータは本質的にビットのシーケンス1であり、根本的に似ていますが、すべてのデータはそれぞれ独自の役割を果たします。JavaScriptのシステムでは、このデータのほとんどは、値と呼ばれるものに見事に分割されています。各値には型があり、それが果たせる役割の種類を決定します。値には6つの基本的な型があります。数値、文字列、ブール値、オブジェクト、関数、および未定義値です。
¶ 値を作成するには、その名前を呼び出すだけです。これは非常に便利です。値のための材料を集めたり、それにお金を払ったりする必要はありません。呼び出すだけで、シューッと手に入ります。もちろん、何もないところから作られるわけではありません。すべての値はどこか(メモリ)に保存する必要があり、同時に膨大な数の値を使用したい場合、コンピュータのメモリが不足する可能性があります。幸い、これはすべての値を同時に必要とする場合にのみ問題となります。値を使用しなくなるとすぐに、それは消散し、わずかなビットだけを残します。これらのビットは、次世代の値を作るために再利用されます。
¶ 数値型は、推測できるように、数値です。数値は通常の数値のように記述されます。
144
¶ それをコンソールに入力すると、出力ウィンドウに同じものが表示されます。入力したテキストは数値を生み出し、コンソールはその数値を受け取って画面に再び書き出しました。このような場合、それはかなり無意味な演習ですが、すぐに、より直接的ではない方法で値を生成することになり、それらが生成するものを確認するためにコンソールで「試してみる」ことが役立つ場合があります。
0100000001100010000000000000000000000000000000000000000000000000
¶ 上の数値は64ビットです。JavaScriptの数値は常に64ビットです。これには重要な影響があります。表現できる数値の種類には限りがあります。3桁の10進数では、0から999までの数値しか記述できません。これは103 = 1000個の数値です。64ビットの2進数では、264個の数値を記述できます。これは非常に多く、1019(1の後にゼロが19個)よりも大きいです。
¶ しかし、1019以下のすべての整数がJavaScriptの数値に収まるわけではありません。まず、負の数もあるので、ビットの1つは数値の符号を格納するために使用されなければなりません。さらに大きな問題は、小数も表現しなければならないことです。これを行うために、11ビットを使用して、数値内の小数点の位置を格納します。
¶ そのため、52ビット3が残ります。252(1015より大きい)未満の任意の整数は、JavaScriptの数値に確実に収まります。ほとんどの場合、使用している数値はそれをはるかに下回っているので、ビットをまったく気にしなくても済みます。それは良いことです。ビットに特に反対しているわけではありませんが、何かを行うには非常に多くのビットが必要です。可能な限り、より大きなものに取り組む方が楽しいです。
¶ 小数は、ドットを使用して記述します。
9.81
¶ 非常に大きくても小さくても、e
を追加し、その後に数値の指数を付けることで、「科学的」表記法を使用することもできます。
2.998e8
¶ これは2.998 * 108 = 299800000です。
¶ 52ビットに収まる整数(整数とも呼ばれる)を使用した計算は、常に正確であることが保証されています。残念ながら、小数を使用した計算は一般的に正確ではありません。π(パイ)は有限の桁数で正確に表現できないのと同様に、多くの数値は、64ビットしか使用できない場合に精度を失います。これは残念ですが、非常に特殊な状況でのみ実際的な問題を引き起こします。重要なのは、それを認識し、小数のデジタル数値を近似値として扱い、正確な値として扱わないことです。
¶ 数値で主に実行する操作は算術演算です。加算や乗算などの算術演算は、2つの数値を取り、それらから新しい数値を生成します。JavaScriptでの記述方法は次のとおりです。
100 + 4 * 11
¶ +
と*
記号は演算子と呼ばれます。最初のものは加算を表し、2番目のものは乗算を表します。2つの値の間に演算子を配置すると、それらの値に適用され、新しい値が生成されます。
¶ この例は「4と100を加算し、その結果に11を乗算する」という意味ですか、それとも乗算が加算の前に実行されますか?推測したとおり、乗算が最初に実行されます。しかし、数学と同様に、加算を括弧で囲むことで変更できます。
(100 + 4) * 11
¶ 減算には-
演算子があり、除算は/
で行うことができます。括弧がない状態で演算子が一緒に表示されると、適用される順序は、演算子の優先順位によって決定されます。最初の例は、乗算の優先順位が加算よりも高いことを示しています。除算と乗算は常に減算と加算の前に実行されます。同じ優先順位の複数の演算子が互いに隣り合っている場合(1 - 1 + 1
)、それらは左から右に適用されます。
¶ これが生成する値を推測してから、実行して正しかったかどうかを確認してみてください…
115 * 4 - 4 + 88 / 2
¶ 優先順位のこれらのルールは、心配する必要はありません。わからない場合は、括弧を追加するだけです。
¶ おそらくあまり馴染みのない算術演算子がもう1つあります。%
記号は剰余演算を表すために使用されます。X % Y
は、X
をY
で除算した剰余です。たとえば、314 % 100
は14
、10 % 3
は1
、144 % 12
は0
です。剰余の優先順位は、乗算と除算と同じです。
¶ 次のデータ型は文字列です。数値の場合のように、名前からその用途は明らかではありませんが、非常に基本的な役割も果たします。文字列はテキストを表すために使用され、その名前は、文字をいくつかつなぎ合わせるという事実から派生していると考えられます。文字列は、その内容を引用符で囲んで記述します。
"Patch my boat with chewing gum."
¶ 二重引用符の間にはほとんど何でも入れることができ、JavaScriptはそこから文字列値を作成します。しかし、いくつかの文字は扱いにくいです。引用符を引用符で囲むのが難しいのは想像できるでしょう。改行(Enterキーを押すと表示されるもの)も引用符で囲むことはできません。文字列は1行に収まる必要があります。
¶ このような文字を文字列に含めることができるように、次のトリックが使用されます。引用符で囲まれたテキスト内にバックスラッシュ( '\
')が見つかるたびに、その後の文字に特別な意味があることを示します。バックスラッシュの前にある引用符は文字列を終了せず、その一部になります。バックスラッシュの後に 'n
' 文字が現れると、改行として解釈されます。同様に、バックスラッシュの後の 't
' はタブ文字4を意味します。
"This is the first line\nAnd this is the second"
¶ コンソールに入力すると、引用符とバックスラッシュのエスケープを含む「ソース」形式で表示されることに注意してください。実際のテキストだけを表示するには、print("a\nb")
と入力します。それが正確に何をやるのかは、もう少し後で説明します。
¶ もちろん、バックスラッシュを文字列内の単なるバックスラッシュとして扱い、特別なコードとして扱わないようにしたい状況もあります。2つのバックスラッシュが連続して出現すると、それらは互いに折りたたまれ、結果の文字列値には1つだけが残ります。
"A newline character is written like \"\\n\"."
¶ 文字列は、除算、乗算、または減算できません。+
演算子は文字列に使用できます。加算を行いませんが、連結し、2つの文字列を結合します。
"con" + "cat" + "e" + "nate"
¶ 文字列を操作する方法は他にもありますが、これについては後で説明します。
¶ すべての演算子が記号であるわけではなく、単語として記述されるものもあります。たとえば、typeof
演算子は、渡した値の型を指定する文字列値を生成します。
typeof 4.5
¶ これまで見てきた他の演算子はすべて2つの値を操作していましたが、typeof
は1つだけを取ります。2つの値を使用する演算子は二項演算子と呼ばれ、1つだけを取る演算子は単項演算子と呼ばれます。マイナス演算子は、二項演算子と単項演算子の両方として使用できます。
- (10 - 2)
¶ 次に、ブール型の値があります。これにはtrue
とfalse
の2つしかありません。true
値を生成する方法は次のとおりです。
3 > 2
¶ そして、false
は次のように生成できます。
3 < 2
¶ >
と<
記号は以前に見たことがあると思います。それぞれ、「より大きい」と「より小さい」を意味します。これらは二項演算子であり、それらを適用した結果は、その場合に保持されているかどうかを示すブール値です。
¶ 文字列も同様に比較できます。
"Aardvark" < "Zoroaster"
¶ 文字列の順序付け方法は、ほぼアルファベット順です。ほぼ…大文字は常に小文字よりも「小さい」ため、"Z" < "a"
(大文字のZ、小文字のa)はtrue
であり、非アルファベット文字( '!
'、 '@
'など)も順序に含まれます。比較が行われる実際の方法は、Unicode標準に基づいています。この標準は、ギリシャ語、アラビア語、日本語、タミル語などの文字を含む、実質的に必要なすべての文字に番号を割り当てています。そのような番号を持つことは、コンピュータ内に文字列を格納するのに便利です。文字列を数値のリストとして表現できます。文字列を比較するときは、JavaScriptは文字列内の文字の番号を左から右に比較します。
¶ その他の同様の演算子には、>=
(「以上」)、<=
(「以下」)、==
(「等しい」)、および!=
(「等しくない」)があります。
"Itchy" != "Scratchy"
5e2 == 500
¶ ブール値自身にも適用できる便利な演算がいくつかあります。JavaScriptは、and、or、notの3つの論理演算子をサポートしています。これらはブール値について「推論」するために使用できます。
¶ &&
演算子は論理andを表します。これは二項演算子であり、その結果は、与えられた両方の値がtrue
の場合にのみtrue
になります。
true && false
¶ ||
は論理orであり、与えられた値のいずれかがtrue
であればtrue
になります。
true || false
¶ Notは感嘆符!
で記述され、与えられた値を反転させる単項演算子です。!true
はfalse
であり、!false
はtrue
です。
((4 >= 6) || ("grass" != "green")) && !(((12 * 2) == 144) && true)
¶ これは正しいですか?可読性のために、不要な括弧が多く含まれています。この簡略版は同じ意味です。
(4 >= 6 || "grass" != "green") && !(12 * 2 == 144 && true)
¶ 括弧が必要な場合が常に明らかなわけではありません。実際には、これまで見てきた演算子の中で、||
が最も低い優先順位を持ち、次に&&
、次に比較演算子(>
、==
など)、そして残りの演算子が続きます。これは、単純なケースでできるだけ少ない括弧で済むように選択されています。
¶ これまでのすべての例では、ポケット電卓のように言語を使用しています。いくつかの値を作成し、演算子を適用して新しい値を取得します。このような値の作成は、すべてのJavaScriptプログラムの不可欠な部分ですが、それは一部に過ぎません。値を生成するコードは式と呼ばれます。直接記述された値(22
や"psychoanalysis"
など)はすべて式です。括弧で囲まれた式も式です。そして、2つの式に適用された二項演算子、または1つの式に適用された単項演算子も式です。
¶ 式を構築する方法は他にもいくつかありますが、適切な時期に明らかになります。
¶ 式よりも大きな単位が存在します。それは文と呼ばれます。プログラムは文のリストとして構築されます。ほとんどの文はセミコロン(;
)で終わります。最も単純な種類の文は、セミコロンの後の式です。これはプログラムです。
1; !false;
¶ これは役に立たないプログラムです。式は値を生成するだけで済みますが、文は何かしらの方法で世界を変える場合にのみ意味を持ちます。画面に何かを出力する(それは世界を変えることに相当します)、または後続の文に影響を与える方法でプログラムの内部状態を変更することができます。これらの変更は「副作用」と呼ばれます。上記の例にある文は、1
とtrue
の値を生成するだけで、すぐにビットバケット5に捨てます。これは世界に何の影響も与えず、副作用ではありません。
¶ プログラムは内部状態をどのように維持しますか?どのようにして物事を記憶しますか?古い値から新しい値を生成する方法を見てきましたが、これは古い値を変更せず、新しい値はすぐに使用しないと再び消散します。値を捕捉して保持するために、JavaScriptは変数と呼ばれるものを提供します。
var caught = 5 * 5;
¶ 変数は常に名前を持ち、値を指して保持することができます。上記の文はcaught
という変数を作成し、それを用いて5
に5
を掛けた結果の数値を保持します。
¶ 上記のプログラムを実行した後、コンソールにcaught
という単語を入力すると、値25
を取得できます。変数の名前は、その値を取得するために使用されます。caught + 1
も機能します。変数名は式として使用できるため、より大きな式の一部になることができます。
¶ var
という単語は、新しい変数を作成するために使用されます。var
の後に、変数の名前が続きます。変数名にはほとんどすべての単語を使用できますが、スペースを含めることはできません。数字を変数名の一部として使用できます(catch22
は有効な名前です)。ただし、名前は数字で始めることはできません。文字 '$
' と '_
' は、文字のように名前で使用できるため、$_$
は正しい変数名です。
¶ 新しい変数がすぐに値を捕捉するようにしたい場合(多くの場合そうなる)、=
演算子を使用して、ある式の値を与えることができます。
¶ 変数が値を指している場合、それがその値に永遠に結び付けられるという意味ではありません。いつでも=
演算子を既存の変数で使用して、それらを現在の値から引き離し、新しい値を指すようにすることができます。
caught = 4 * 4;
¶ 変数は箱ではなく、触手として想像する必要があります。値を含むのではなく、つかむのです。2つの変数が同じ値を参照できます。プログラムがまだ保持している値のみアクセスできます。何かを覚えたいときは、触手を伸ばしてそれを保持するか、既存の触手の1つを新しい値に接続し直します。ルイージがまだあなたに借りているドルの額を覚えるには、次のようにすることができます。
var luigiDebt = 140;
¶ その後、ルイージが何かを返済するたびに、変数に新しい数値を与えることで、この金額を減らすことができます。
luigiDebt = luigiDebt - 35;
¶ 特定の時間に存在する変数と値の集合は環境と呼ばれます。プログラムが起動すると、この環境は空ではありません。常に多数の標準変数が含まれています。ブラウザがページを読み込むと、新しい環境を作成し、これらの標準値をそれにアタッチします。そのページのプログラムによって作成および変更された変数は、ブラウザが新しいページに移動するまで存続します。
¶ 標準環境によって提供される値の多くは、「関数」という型を持っています。関数は、値にラップされたプログラムの一部です。一般的に、このプログラムの一部は何か便利なことを行い、それを含む関数値を使用して呼び出すことができます。ブラウザ環境では、変数alert
は、メッセージを含む小さなダイアログウィンドウを表示する関数を保持しています。これは次のように使用されます。
alert("Avocados");
¶ 関数内のコードを実行することを呼び出し、または適用と言います。これを行うための表記法は括弧を使用します。関数値を生成するすべての式は、その後に括弧を付けることで呼び出すことができます。この例では、値"Avocados"
が関数に与えられ、ダイアログウィンドウに表示するテキストとして使用されます。関数に与えられる値はパラメータまたは引数と呼ばれます。alert
は1つだけ必要ですが、他の関数は異なる数が必要な場合があります。
¶ ダイアログウィンドウを表示することは副作用です。多くの関数は、生成する副作用のために役立ちます。関数が値を生成することも可能であり、その場合は、役に立つために副作用を持つ必要はありません。たとえば、Math.max
という関数があり、任意の数の数値引数を取り、最大の値を返します。
alert(Math.max(2, 4));
¶ 関数が値を生成する場合、それを返すと言います。値を生成するものは常にJavaScriptでは式であるため、関数呼び出しはより大きな式の一部として使用できます。
alert(Math.min(2, 4) + 100);
¶ 前の例が示すように、alert
は式の結果を表示するのに役立ちます。しかし、それらの小さなウィンドウをすべてクリックするのは煩わしいので、ウィンドウを表示するのではなく、コンソールの出力領域に値を書き込む同様の関数であるprint
を使用することをお勧めします。print
は標準的なJavaScript関数ではなく、ブラウザはそれを提供しませんが、本書で利用可能になっているため、これらのページで使用できます。
print("N");
¶ これらのページでも提供されている同様の関数はshow
です。print
は引数をプレーンテキストとして表示しますが、show
はプログラム内での表示方法を試みるため、値の型に関するより多くの情報を提供できます。たとえば、文字列値は、show
に渡されると引用符を保持します。
show("N");
¶ ブラウザによって提供される標準環境には、ウィンドウを表示するための関数が他にもいくつか含まれています。confirm
を使用して、ユーザーにOK/キャンセル質問をすることができます。これはブール値を返し、ユーザーが「OK」を押すとtrue
、ユーザーが「キャンセル」を押すとfalse
になります。
show(confirm("Shall we, then?"));
¶ prompt
を使用して、「オープン」な質問をすることができます。最初の引数は質問で、2番目の引数はユーザーが開始するテキストです。テキスト行をウィンドウに入力でき、関数はそれを文字列として返します。
show(prompt("Tell us everything you know.", "..."));
¶ 環境内のほとんどすべての変数に新しい値を与えることができます。これは便利ですが、危険でもあります。print
に値8
を与えると、もう何も印刷できなくなります。幸いなことに、コンソールには大きな「リセット」ボタンがあり、環境を元の状態にリセットできます。
¶ 1行のプログラムはあまり面白くありません。複数の文をプログラムに配置すると、予測どおり、文は上から下へ順番に実行されます。
var theNumber = Number(prompt("Pick a number", "")); print("Your number is the square root of " + (theNumber * theNumber));
¶ 関数Number
は値を数値に変換します。これは、prompt
の結果が文字列値であるため、この場合必要です。String
とBoolean
という同様の関数があり、値をそれらの型に変換します。
¶ 0から12までのすべての偶数をプリントアウトするプログラムを考えてみましょう。これを記述する1つの方法は次のとおりです。
print(0); print(2); print(4); print(6); print(8); print(10); print(12);
¶ これは機能しますが、プログラムを作成するという考え方は、作業を減らすことであり、増やすことではありません。1000未満のすべての偶数が必要な場合、上記は実行不可能です。必要なのは、コードを自動的に繰り返す方法です。
var currentNumber = 0; while (currentNumber <= 12) { print(currentNumber); currentNumber = currentNumber + 2; }
¶ 導入章でwhile
を見たことがあるかもしれません。while
という単語で始まる文はループを作成します。ループは、文のシーケンスにおける乱れです。プログラムがいくつかの文を複数回繰り返す原因となる可能性があります。この場合、while
という単語の後に括弧で囲まれた式が続きます(括弧は必須です)。これは、ループがループするか終了するかを判断するために使用されます。この式によって生成されたブール値がtrue
である限り、ループ内のコードは繰り返されます。falseになるとすぐに、プログラムはループの一番下に行き、通常どおり続行します。
¶ 変数currentNumber
は、変数がプログラムの進捗状況を追跡する方法を示しています。ループが繰り返されるたびに、2
ずつ増加し、各繰り返しの一番初めに、12
と比較して、ループを続けるかどうかを決定します。
¶ while
文の3番目の部分は別の文です。これはループの本体であり、複数回実行する必要があるアクションまたはアクションです。数値を印刷する必要がない場合、プログラムは次のようになります。
var currentNumber = 0; while (currentNumber <= 12) currentNumber = currentNumber + 2;
¶ ここで、currentNumber = currentNumber + 2;
はループの本体を形成する文です。ただし、数値も印刷する必要があるため、ループ文は複数の文で構成する必要があります。中括弧({
と}
)を使用して、文をブロックにグループ化します。ブロック外の外部の世界では、ブロックは単一の文としてカウントされます。以前の例では、これを使用して、print
への呼び出しとcurrentNumber
を更新する文の両方をループに含めています。
¶ これまで示した手法を使用して、210(2の10乗)の値を計算して表示するプログラムを作成します。明らかに、2 * 2 * ...
と書くだけの安易な方法は使用できません。
¶ これについて苦労している場合は、偶数例で考えてみてください。プログラムは一定回数アクションを実行する必要があります。while
ループを持つカウンタ変数は、そのため使用できます。カウンタを印刷する代わりに、プログラムは何かを2倍する必要があります。この何かは別の変数で、その中に結果の値が構築されます。
¶ この方法がまだよくわからない場合でも心配しないでください。この章で説明するすべてのテクニックを完全に理解していても、特定の問題に適用するのは難しい場合があります。コードの読み書きはこれに対する感覚を養うのに役立つため、解決策を研究し、次の練習問題を試してみてください。
¶ わずかな修正を加えることで、前の練習問題の解決策を使用して三角形を描くことができます。そして、「三角形を描く」と言うとき、私は「目を細めるとほぼ三角形に見えるテキストを出力する」という意味です。
¶ 10行出力します。最初の行には1つの「#」文字があります。2番目には2つあります。以下同様です。
¶ X個の「#」文字を含む文字列をどのように取得しますか?1つの方法は、ループ内のループ(入れ子ループ)を使用して、必要なときに毎回構築することです。より簡単な方法は、ループの前の反復で使用した文字列を再利用し、それに1文字を追加することです。
var line = ""; var counter = 0; while (counter < 10) { line = line + "#"; print(line); counter = counter + 1; }
¶ いくつかの文の前に付けたスペースに気づいたと思います。これらは必須ではありません。コンピュータはスペースなしでもプログラムを受け入れます。実際、プログラムの改行もオプションです。必要であれば1つの長い行として記述することもできます。ブロック内のインデントの役割は、コードの構造を閲覧者にとってより明確にすることです。新しいブロックを他のブロックの中に開くことができるため、複雑なコードでは、1つのブロックがどこで終わり、別のブロックが始まるのかを見分けるのが難しくなることがあります。行がインデントされている場合、プログラムの視覚的な形状は、その中のブロックの形状に対応します。私は各オープンブロックに2つのスペースを使用しますが、好みは異なります。
¶ プログラムを入力できるコンソールのフィールドは、これらのスペースを自動的に追加することで役立ちます。最初は煩わしいように思えるかもしれませんが、多くのコードを作成すると、非常に大きな時間節約になります。Shift+Tabを押すと、カーソルが現在置かれている行のインデントが変更されます。
¶ 場合によっては、JavaScriptで文末のセミコロンを省略できます。他の場合では、セミコロンがないと奇妙なことが発生します。安全に省略できる場合の規則は複雑で奇妙です。この本では、セミコロンを省略せず、自分のプログラムでも同じようにすることを強くお勧めします。
¶ これまで見てきたwhile
の使用方法には、すべて同じパターンが表示されています。まず、「カウンタ」変数が作成されます。この変数はループの進捗状況を追跡します。while
自体にはチェックが含まれており、通常はカウンタが既にいくつかの境界に達したかどうかを確認します。次に、ループ本体の最後に、カウンタが更新されます。
¶ 多くのループはこのパターンに当てはまります。このため、JavaScriptや同様の言語では、より短く、より包括的な形式も提供されています。
for (var number = 0; number <= 12; number = number + 2) show(number);
¶ このプログラムは、以前の偶数印刷の例と完全に同等です。唯一の違いは、ループの「状態」に関連するすべての文が1行になっていることです。for
の後の括弧には、2つのセミコロンを含める必要があります。最初のセミコロンの前にある部分はループを初期化し、通常は変数を定義します。2番目の部分は、ループをまだ続ける必要があるかどうかをチェックする式です。最後の部分はループの状態を更新します。ほとんどの場合、これはwhile
構造よりも短く、明確です。
¶ 私はいくつかの変数名でかなり奇妙な大文字化を使用してきました。これらの名前にスペースを含めることができないため(コンピュータはそれらを2つの別々の変数として読み取ります)、複数の単語で構成される名前の選択肢は、fuzzylittleturtle
、fuzzy_little_turtle
、FuzzyLittleTurtle
、またはfuzzyLittleTurtle
などにほぼ限定されます。最初のものは読みづらいため、個人的にはアンダースコアを使用するものが好きですが、入力するのは少し面倒です。ただし、標準的なJavaScript関数とほとんどのJavaScriptプログラマは最後のものに従います。そのような小さなことに慣れるのは難しくないので、私は大衆に従って最初の単語の後の各単語の最初の文字を大文字にします。
¶ Number
関数など、一部のケースでは、変数の最初の文字も大文字になります。これは、この関数をコンストラクタとしてマークするために実行されました。コンストラクタとは何かについては、第8章で説明します。今のところ、重要なのは、この明らかな一貫性のなさについて気にしないことです。
¶ var
、while
、for
など、特別な意味を持つ名前は、変数名として使用できないことに注意してください。これらはキーワードと呼ばれます。将来のバージョンのJavaScriptで「使用するために予約されている」単語も多数あります。これらは正式には変数名として使用することは許可されていませんが、一部のブラウザでは許可されています。完全なリストは非常に長いです。
abstract boolean break byte case catch char class const continue debugger default delete do double else enum export extends false final finally float for function goto if implements import in instanceof int interface long native new null package private protected public return short static super switch synchronized this throw throws transient true try typeof var void volatile while with
¶ 今はこれらを暗記する必要はありませんが、予期したとおりに動作しない場合、これが問題である可能性があることを覚えておいてください。私の経験では、char
(1文字の文字列を格納するため)とclass
は、誤って使用される最も一般的な名前です。
¶ 前の2つの練習問題の解決策をwhile
ではなくfor
を使用して書き直してください。
var result = 1; for (var counter = 0; counter < 10; counter = counter + 1) result = result * 2; show(result);
¶ '{
'でブロックが開かれていなくても、ループ内の文はそれでも2つのスペースがインデントされ、上記の行に「属している」ことが明確になります。
var line = ""; for (var counter = 0; counter < 10; counter = counter + 1) { line = line + "#"; print(line); }
¶ プログラムは多くの場合、前の値に基づいた値で変数を「更新」する必要があります。たとえば、counter = counter + 1
。JavaScriptはこれのショートカットを提供します。counter += 1
。これは他の多くの演算子にも機能します。たとえば、result *= 2
はresult
の値を2倍にするか、counter -= 1
はカウントを減らすことができます。
¶ counter += 1
とcounter -= 1
には、さらに短いバージョンがあります。counter++
とcounter--
です。
¶ ループは、プログラムの制御フローに影響を与えると言われています。これらは、文が実行される順序を変更します。多くの場合、別の種類のフローが役立ちます。文をスキップすることです。
¶ 20未満で、3と4の両方で割り切れるすべての数値を表示したいと考えています。
for (var counter = 0; counter < 20; counter++) { if (counter % 3 == 0 && counter % 4 == 0) show(counter); }
¶ キーワードif
は、キーワードwhile
とあまり違いはありません。指定された条件(括弧内)をチェックし、この条件に基づいてその後の文を実行します。ただし、これは一度だけ行われるため、文は0回または1回実行されます。
¶ 剰余(%
)演算子のトリックは、数値が別の数値で割り切れるかどうかをテストする簡単な方法です。割り切れる場合、剰余演算子が返す除算の剰余はゼロになります。
¶ 20未満のすべての数値を印刷したいが、4で割り切れない数値を括弧で囲みたい場合は、次のように行うことができます。
for (var counter = 0; counter < 20; counter++) { if (counter % 4 == 0) print(counter); if (counter % 4 != 0) print("(" + counter + ")"); }
¶ しかし、プログラムはcounter
が4
で2回割り切れるかどうかを判定する必要があります。同じ効果は、if
文の後にelse
節を追加することで得られます。else
文は、if
の条件が偽の場合にのみ実行されます。
for (var counter = 0; counter < 20; counter++) { if (counter % 4 == 0) print(counter); else print("(" + counter + ")"); }
¶ この簡単な例をもう少し拡張して、同じ数値を出力しますが、15より大きい場合はその後に星を2つ、10より大きく15以下であれば星を1つ、それ以外は星をつけないで出力するようにしてみましょう。
for (var counter = 0; counter < 20; counter++) { if (counter > 15) print(counter + "**"); else if (counter > 10) print(counter + "*"); else print(counter); }
¶ これは、if
文を連鎖させることができることを示しています。この場合、プログラムはまずcounter
が15
より大きいかどうかを確認します。もし大きければ、星が2つ出力され、他のテストはスキップされます。そうでなければ、counter
が10
より大きいかどうかを確認します。counter
が10
より大きくない場合にのみ、最後のprint
文に到達します。
¶ prompt
を使って、2 + 2の値を尋ねるプログラムを作成してください。答えが「4」であれば、alert
を使って褒めるメッセージを表示します。「3」または「5」であれば、「惜しい!」と表示します。その他の場合は、厳しいメッセージを表示します。
var answer = prompt("You! What is the value of 2 + 2?", ""); if (answer == "4") alert("You must be a genius or something."); else if (answer == "3" || answer == "5") alert("Almost!"); else alert("You're an embarrassment.");
¶ ループが常に最後まで実行する必要がない場合、break
キーワードが役立ちます。これは、現在のループからすぐに飛び出し、ループの後に続行します。このプログラムは、20以上で7で割り切れる最初の数値を見つけます。
for (var current = 20; ; current++) { if (current % 7 == 0) break; } print(current);
¶ 上記のfor
構文には、ループの終わりをチェックする部分がありません。つまり、停止するには内部のbreak
文に依存しているということです。同じプログラムは、次のように単純に書くこともできます...
for (var current = 20; current % 7 != 0; current++) ; print(current);
¶ この場合、ループの本体は空です。空の文を作るには、単独のセミコロンを使用できます。ここでは、ループの効果は変数current
を目的の値にインクリメントすることだけです。しかし、私はbreak
を使用する例が必要だったので、最初のバージョンにも注意してください。
¶ 前の練習問題の解答にwhile
と必要に応じてbreak
を追加して、正しい答えが返されるまで質問を繰り返し続けるようにしてください。
¶ while (true) ...
は、それ自体では終了しないループを作成するために使用できます。これは少しばかげているかもしれませんが、プログラムにtrue
がtrue
である限りループするように要求することですが、便利なテクニックです。
var answer; while (true) { answer = prompt("You! What is the value of 2 + 2?", ""); if (answer == "4") { alert("You must be a genius or something."); break; } else if (answer == "3" || answer == "5") { alert("Almost!"); } else { alert("You're an embarrassment."); } }
¶ 最初のif
の本体に2つの文があるため、すべての本体に中括弧を追加しました。これは好みの問題です。一部の本体がブロックで、他の本体が単一の文であるif
/else
連鎖は、少し不均衡に見えますが、それについてはご自身で判断してください。
¶ 別の解法。論理的には優れているが、break
を使用していない。
var value = null; while (value != "4") { value = prompt("You! What is the value of 2 + 2?", ""); if (value == "4") alert("You must be a genius or something."); else if (value == "3" || value == "5") alert("Almost!"); else alert("You're an embarrassment."); }
¶ 前の練習問題の解答には、var answer;
という文があります。これはanswer
という名前の変数を生成しますが、値は代入しません。この変数の値を取得しようとすると何が起こるか?
var mysteryVariable; show(mysteryVariable);
¶ 触手の観点から言えば、この変数は空中で終わっており、掴むものがない。空の場所の値を要求すると、undefined
という特別な値が得られます。print
やalert
など、興味深い値を返さない関数は、undefined
値も返します。
show(alert("I am a side effect."));
¶ 同様の値として、null
もあります。これは「この変数は定義されているが、値を持っていない」という意味です。undefined
とnull
の意味の違いは、主に学術的なものであり、通常はあまり重要ではありません。実際的なプログラムでは、何かが「値を持っているかどうか」をチェックする必要があることがよくあります。このような場合、something == undefined
という式を使用できます。なぜなら、厳密に同じ値ではないとしても、null == undefined
はtrue
を生成するからです。
¶ さて、別の難しい話題に移りましょう...
show(false == 0); show("" == 0); show("5" == 5);
¶ これらはすべてtrue
の値を返します。型が異なる値を比較する場合、JavaScriptは複雑で分かりにくいルールセットを使用します。正確に説明しようとはしませんが、ほとんどの場合、一方の値をもう一方の値の型に変換しようとします。しかし、null
またはundefined
が発生した場合、両方がnull
またはundefined
の場合にのみtrue
を生成します。
¶ 変数がfalse
の値を参照しているかどうかをテストしたい場合はどうすればよいでしょうか?文字列と数値をブール値に変換するルールでは、0
と空の文字列はfalse
としてカウントされ、その他の値はすべてtrue
としてカウントされます。このため、variable == false
という式は、variable
が0
または""
を参照する場合にもtrue
になります。このような場合、自動的な型変換を発生させたくない場合、===
と!==
という2つの追加演算子があります。前者は値が正確に等しいかどうかをテストし、後者は正確に等しくないかどうかをテストします。
show(null === undefined); show(false === 0); show("" === 0); show("5" === 5);
¶ これらはすべてfalse
です。
¶ if
、while
、for
文の条件として与えられる値は、ブール値である必要はありません。チェックされる前に、自動的にブール値に変換されます。つまり、数値0
、空の文字列""
、null
、undefined
、そしてもちろんfalse
はすべて偽としてカウントされます。
¶ 他のすべての値がこの場合true
に変換されるという事実は、多くの状況で明示的な比較を省略することを可能にします。変数が文字列またはnull
のいずれかを含むことがわかっている場合、次のように非常に簡単にチェックできます...
var maybeNull = null; // ... mystery code that might put a string into maybeNull ... if (maybeNull) print("maybeNull has a value");
¶ ...ただし、謎のコードがmaybeNull
に""
の値を与える場合を除きます。空の文字列は偽なので、何も出力されません。あなたがやろうとしていることによっては、これは間違っている可能性があります。このような場合、微妙な間違いを防ぐために、明示的な=== null
または=== false
を追加することをお勧めします。数値が0
である可能性のある数値についても同様です。
¶ 前の例の「謎のコード」について説明している行は、少し疑わしく見えたかもしれません。プログラムに余分なテキストを含めることは、しばしば役立ちます。これの最も一般的な用途は、人間が理解できる言語でプログラムに説明を追加することです。
// The variable counter, which is about to be defined, is going // to start with a value of 0, which is zero. var counter = 0; // Now, we are going to loop, hold on to your hat. while (counter < 100 /* counter is less than one hundred */) /* Every time we loop, we INCREMENT the value of counter, Seriously, we just add one to it. */ counter++; // And then, we are done.
¶ この種のテキストはコメントと呼ばれます。ルールは以下のとおりです。「/*
」は、次の「*/
」が見つかるまで続くコメントを開始します。「//
」は、行末まで続く別の種類のコメントを開始します。
¶ ご覧のように、単純なプログラムでも、コメントをたくさん追加するだけで、大きく、見苦しく、複雑に見せることができます。
¶ 自動型変換が発生する他の状況もあります。非文字列の値を文字列に追加すると、値は連結される前に自動的に文字列に変換されます。数値と文字列を掛け合わせると、JavaScriptは文字列から数値を作成しようとします。
show("Apollo" + 5); show(null + "ify"); show("5" * 5); show("strawberry" * 5);
¶ 最後の文はNaN
を出力します。これは特別な値です。「数値ではない」を表し、数値型です(少し矛盾しているように聞こえるかもしれません)。この場合、イチゴは数値ではないという事実を表しています。NaN
の値に対するすべての算術演算はNaN
になります。そのため、例のように5
を掛け算しても、NaN
の値のままです。また、これは時に混乱を招く可能性がありますが、NaN == NaN
はfalse
になります。値がNaN
かどうかを確認するには、isNaN
関数を使用できます。NaN
は、ブール値に変換されたときに偽としてカウントされる別の(最後の)値です。
¶ これらの自動変換は非常に便利ですが、かなり奇妙でエラーが発生しやすいものです。+
と*
はどちらも算術演算子ですが、例では完全に異なる動作をします。私のコードでは、+
を文字列と非文字列を組み合わせるために多く使用していますが、文字列値に対して*
や他の数値演算子を使用しないようにしています。数値を文字列に変換することは常に可能で簡単ですが、文字列を数値に変換することは機能しない場合もあります(例の最後の行のように)。Number
を使用して文字列を数値に明示的に変換することで、NaN
値を取得するリスクがあることを明確に示すことができます。
show(Number("5") * 5);
¶ 前にブール演算子&&
と||
について説明した際、それらがブール値を生成すると主張しました。これは少し単純化しすぎていることが判明しました。それらをブール値に適用すると、確かにブール値を返します。しかし、他の種類の値にも適用でき、その場合は引数の1つを返します。
¶ ||
が実際に行うことは次のとおりです。まず、その左側の値を確認します。この値をブール値に変換するとtrue
が生成される場合、この左側の値を返し、そうでない場合は右側の値を返します。引数がブール値の場合に正しく動作することをご自身で確認してください。なぜそのような動作をするのでしょうか?これは非常に実用的であることがわかります。次の例を考えてみましょう。
var input = prompt("What is your name?", "Kilgore Trout"); print("Well hello " + (input || "dear"));
¶ ユーザーが「キャンセル」を押すか、名前を入力せずに他の方法でprompt
ダイアログを閉じると、変数input
にはnull
または""
の値が保持されます。これらは両方とも、ブール値に変換するとfalse
になります。この場合、input || "dear"
という式は、「変数input
の値、または文字列"dear"
」と解釈できます。「フォールバック」値を提供する簡単な方法です。
¶ &&
演算子は同様に機能しますが、逆です。左側の値がブール値に変換されたときにfalse
を返すようなものの場合、その値を返し、そうでない場合は右側の値を返します。
¶ これらの2つの演算子のもう一つの特性として、右辺の式は必要な場合にのみ評価されるという点が挙げられます。true || X
の場合、X
がどのような値であっても結果は true
となるため、X
は決して評価されず、副作用がある場合も発生しません。false && X
についても同様です。
false || alert("I'm happening!"); true || alert("Not me.");
- ビットとは、2値をとるもののことであり、通常は
0
と1
で表されます。コンピュータ内部では、高電圧または低電圧、強い信号または弱い信号、CD表面の光沢のある点またはつや消しの点などの形で表現されます。 - ここで
10010000
のようなものを期待していたなら、鋭い洞察力です。しかし、読み進めてください。JavaScriptの数値は整数として保存されません。 - 実際には53ビットです。これは、1ビットを無料で得ることができるトリックによるものです。詳細に興味のある方は「IEEE 754」フォーマットを調べてみてください。
- コンソールで文字列値を入力すると、入力したとおりに引用符とバックスラッシュが付いた状態で返されることに気付くでしょう。特殊文字を正しく表示するには、
print("a\nb")
を実行します。これがなぜ機能するのかは、すぐに説明します。 - ビットバケットとは、古いビットが保管される場所とされています。一部のシステムでは、プログラマーが手動で定期的に空にする必要があります。幸いなことに、JavaScriptには完全に自動化されたビットリサイクルシステムが備わっています。