コンピュータの中にはデータがあるだけです。データでないものは存在しません。全てのデータは本質的に連続した ビット1 で、根本的には同じですがどのデータにも役割があります。JavaScript システムでは、このデータのほとんどは値と呼ばれるものにきちんと分けられます。どの値にもタイプがあり、それによって役割が決まります。6 つの基本タイプ、数字、文字列、ブール型、オブジェクト、関数、および未定義値、があります。
値を名前を呼び出すだけで値が作成されます。非常に便利です。建築用資材を集める必要も、代価を払う必要もありません。ヒューッ と呼べば、値がそこにあります。もちろん無から作り出されるのではありません。どの値も何処かに保存しておかなければなりません。大量の値を使おうとすると、コンピューターのメモリーを使い果たしてしまうかもしれません。しかし全ての値を同時に必要とした場合に問題になるだけで、値が必要でなくなれば、数ビットを残して姿を消します。これらのビットはリサイクルされて次の世代の値になります。
数字タイプの値は、ご推察のとおり、数値です。数字と同じように書きます:
144
コンソールから入力したと同じものが出力ウィンドウに表示されます。タイプしたテキストが数値を発生させ、コンソールがその数字をスクリーンに書き込んだのです。何のための練習か分からなかったでしょうが、やがて直接的ではないにしても値を作り出し、コンソールで '試した' ことが役に立ったことがお分かりいただけると思います。144 はビット2 で表すと次のようになります:
0100000001100010000000000000000000000000000000000000000000000000
上記の数字は 64 ビットです。JavaScript では常に 64 ビットで表します。これは重大な影響を及ぼします: 異なる数字を表現できる数には制限があり、3 桁の 10 進数で書けるのはは 0 から 999 まで、10^3 = 1000 桁の数です。64 ビットだと 2^64 で、10^19 桁 (ゼロが 19 個) の数字になります。
しかし JavaScript では 10^19 個の整数が全て使えるわけではありません。なかには負数もあるので、1 ビットを符号を保存するために使います。さらに問題なのは、非整数も表さなければならないことです。このため、11 ビットを小数点の位置の保存に使います。
52 ビット3 残ります。多くの場合、2^52、つまり 10^15 桁で JavaScript で使われる数には支障ありません。したがってビットのことを心配する必要はありません。良いことです。私には特に問題はありませんが、もっと極端に大きな数を扱う 必要がある 方もいらっしゃるでしょう。より大きい数を扱えたらより快適になるでしょう。少数はドットを使って書きます。
9.81
非常に大きいまたは非常に小さい数の場合、e を付けて指数を続ける '科学的記数法' を使うことができます:
2.998e8
2.998 * 10^8 = 299800000 になります。
52 ビットの整数計算では常にその正確さが保証されます。しかし小数の計算では概してそうではありません。π (パイ) が限られた数の 10 進数では正確に表せないように、64 ビットでは多くの数が正確ではありません。困ったことですが、実際には非常に特別な場合に問題になるにすぎません。重要なのは、そのことに気付いて、小数を正確な値としてではなく近似値として扱うことです。
数字を扱うのは主に算術です。加算や乗算などの算術演算では 2 つの数値から 1 つの産み出します。JavaScript では次のようになります:
100 + 4 * 11
+ 記号や * 記号は演算子と呼ばれます。前者は加算を、後者は乗算を表します。2 つの値の間に演算子を置くと、それが 2 つの値に適用されて 1 つの新しい値が生まれます。この例は '4 と 100 を足し、その結果に 11 を掛ける' という意味でしょうか?それとも足し算の前に掛け算を行うのでしょうか?ご想像通り掛け算が先です。しかし数学では足し算を括弧で囲んでこれを変えることができます:
(100 + 4) * 11
減算には - 演算子が、除算には / 演算子が使われます。複数の演算子が括弧無しで現れた場合は、先の演算子が先に適用されます。最初の例は乗算が加算に先行することを示しています。除算と乗算は常に減算や加算に選考します。同じ優先度の演算子が並んだ場合 (1 - 1 + 1)、左から右の順で適用されます。
次の式の結果を想像し、それから式を実行してその答えが正しいかを確かめてみてください...
115 * 4 - 4 + 88 / 2
これらのルールを気にする必要はありません。確信が持てない場合は括弧を付けてください。
もう一つあまり知られていない算術演算子があります。% 記号はモジュロ演算を表すのに使われます。X モジュロ Y は X 割るY の余りになります。例えば、314 % 100 は 14、10 % 3 は 1、144 % 12 は 0 になります。モジュロは乗算や除算と同じ優先順位です。
次のデータ・タイプは文字列です。その用法は数字のように名前からは明らかではありませんが、非常に基本的な役割を果たします。文字列はテキストを表すのに使われます。その名前は恐らく多くの文字を繋げるという事実に由来します。文字列はその内容を引用符で囲って書かれます:
"Patch my boat with chewing gum."
ほとんど全てのものを二重引用符で囲むことができ、JavaScript はその中から文字列値を作ります。しかし用心しなければならないことが幾つかあります。引用符の間に引用符を置くのが困難であることは想像に易いでしょう。エンター・キーを押した時の改行も、文字列は 1 行に収めなければならないため、引用符で囲むことはできません。
このような文字を文字列に含める場合は次のテクニックを使います: 引用符中のテキスト内のバックスラッシュ ('\') は、その後の文字が特殊な意味を持つことを示します。バックスラッシュの前の引用文で文字列が終わるのではなく、文字列の一部になります。バックスラッシュの後ろの 'n' 文字は改行と解釈されます。同様に、バックスラッシュの後ろの 't' はタブ文字4 の意味を持ちます。
"This is the first line\nAnd this is the second"
もちろん文字列中のバックスラッシュを特殊コードではなくただのバックスラッシュとしたい場合もあります。バックスラッシュが 2 つ続けて現れると、互いにつぶし合い、1 つだけが文字列値に残ります:
"A newline character is written like \"\\n\"."
文字列は割ることも、掛けることも、引くこともできません。しかし + 演算子を使うことは 可能 です。この場合、2 つの文字列が加えるのではなく、それらを結びつけ、連結します。
"con" + "cat" + "e" + "nate"
他にも文字列を扱う方法がいろいろありますが、これは後で述べます。
全ての演算子がシンボルとは限りません。言葉として書かれるものもあります。例えば typeof 演算子は与えられた値のタイプに名前が付いた文字列値を作ります。
typeof 4.5
今まで見た他の演算子は全て 2 つの値に作用しましたが、typeof は 1 つの値しか取りません。2 つの値を使う演算子を二項演算子、1 つの値を取る演算子を単項演算子 と呼びます。The マイナス演算子は二項演算子としても単項演算子としても使うことができます:
- (10 - 2)
次にブール型の値があります。値は true と false の 2 つしかありません。以下は true 値を得る例です:
3 > 2
false は次のようにして得ることができます:
3 < 2
> 記号や < 記号は既にご存知でしょう。それぞれ '~よりも大きい' と '~よりも小さい' を意味します。これらは二項演算子で、この場合はどうかの結果を示すブール値です。
文字列も同じ方法で比較することができます:
"Aardvark" < "Zoroaster"
文字列はアルファベットの大きいか小さいかで較べられます。大きいか小さいか... 大文字は常に小文字よりも '小さい' ため、"Z" < "a" は true です。非アルファベット文字 ('!', '@' 等) もこの比較に含まれます。実際の比較方法はユニコード標準に基づいて行われます。この標準は必要となる全ての文字に仮想的に数字を割り当てます。Greek、Arabic、Japanese、Tamil 等の文字が含まれます。このような数字はコンピュータに保存する際に実用的です ― 数字リストとして表すことができます。文字列を比較する際、JavaScript は単に文字列内の文字の番号を左から右に較べていくだけです。
似たような演算子に >= ('等しいか大きい')、<= (等しいか小さい)、== ('等しい')、および != ('等しくない') があります。
"Itchy" != "Scratchy"
5e2 == 50
ブール型の値に使える演算子もあります。JavaScript は 3 つの論理演算子: and、or、および not をサポートしています。これらはブールの '論理化' に使うことができます。
&& 演算子は論理ANDを表します。これは二項演算子で、両方の値が共に true の場合にだけ結果が true になります。
true && false
|| は論理 OR で、どちらかが true の場合に true になります:
true || false
感嘆符 ! と共に書かれる Not は単項演算子で、値を反転させます。!true は false、!false は true になります。
Ex. 2.1
((4 >= 6) || ("grass" != "green")) &&
!(((12 * 2) == 144) && true)
答えは真でしょうか? 読み易くするために余分な括弧が使われています。これをシンプルにすると:
(4 >= 6 || "grass" != "green") &&
!(12 * 2 == 144 && true)
答えは true です。次のように少しずつ減らしていくことができます:
(false || true) && !(false && true)
true && !false
true
"grass" != "green" が true であることにお気付きと思います。Grass は green かもしれませんが、green と等しくありません。
いつ括弧が必要になるか決まっているわけではありません。実際には、これまで見てきた演算子の括弧の必要性が分かればどうにかなります。括弧が少ない順で見てみると、|| が一番少なく、次に &&、次に比較演算子 (>、== 等々)、そして残りという順になります。
これまでの例は全て言語を電卓のように使ってきました。いくつかの値に演算子を使って新しい値にしてみてください。このような値の作成は 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 は有効な名前ですが、1 で始めることはできません。'$' と '_' を文字のように名前に使うことができ、$_$ は正しい変数名です。
よくあることですが、新しい変数ですぐに値をキャッチしたい時は、= 演算子を使ってそれに式の値を与えることができます。
変数が値をポイントしていても、その値にいつまでも縛り付けられているわけではありません。= 演算子で既存の変数を現在値から切り離し、新しい値をポイントさせることができます。
caught = 4 * 4;
変数は箱ではなく、触手のようなものと考えるべきでしょう。変数は値を 容れる ものではなく つかむ ものなのです ― 2 つの変数が同じ値を参照することもあり得ます。プログラムが支配力を持っている値だけが変数でアクセスすることができます。何かを思い出す必要のある時、触手を伸ばしてそれをつかまえるか、既存の触手の 1 つを付け直して新しい値をつかまえます。例えば、Luigi にまだ何ドル貸しているかを思い出すには...
var luigiDebt = 140;
そして Luigi が返済するたびに、この変数に新しい数字を与えて負債額が減っていきます:
luigiDebt = luigiDebt - 35;
ある時点での変数とその値の集合を 環境 と呼びます。プログラムの開始時、この環境は空です。環境には常に複数の標準変数が含まれます。ブラウザーがページをロードすると、新しい環境が作られ、標準値がそれにアタッチされます。プログラムによって作られ修正される変数は、ブラウザーが新しいページに行くまで存続します。
標準環境で提供される値の多くがタイプ '関数' を持ちます。関数は値にラップされたプログラムの一部です。一般的に、プログラムのこの部分は有益なことを行い、関数値を使って呼び出すことができます。ブラウザー環境では変数 alert がダイアログボックスにメッセージを表示する関数を持っています。次のように使います:
alert("Also, your hair is on fire.");
関数内のコードを実行することを 呼び出し または 適用 と呼びます。これを行う表記法には括弧が使われます。関数値を生み出す式は全て後ろに括弧を置いて呼び出すことができます。括弧で囲まれた文字列値は関数に与えられ、関数はそれをテキストのように使ってダイアログボックスに表示します。関数に与えられる値を パラメーター または 引数 と呼びます。alert が必要とする値は 1 つだけですが、他の関数は複数の値を必要とする場合があります。
ダイアログボックスを表示するのは副作用です。関数の多くは副作用を生みます。関数が値を生み出すことも可能ですが、この場合関数は副作用を持つ必要はありません。例えば、関数 Math.max は 2 つの引数を取り、大きいほうを返します:
alert(Math.max(2, 4));
関数が値を生み出すとき、それは 返す と言われます。JavaScript では値を生み出すものは常に式であるため、関数呼び出しはより多きな式の一部として使うことができます:
alert(Math.min(2, 4) + 100);
3 章で関数の書き方を説明します。
上の例が示すように、alert は式の結果を表示するために使うことができます。しかしわざわざクリックしてこの小さなウィンドウを閉じるのにはイライラします。そこでこれからは alert に似た関数 print を使うことにします。この関数はポップアップ・ウィンドウを開かず、値をコンソールの出力領域に表示します。print は JavaScript の標準関数ではなく、ブラウザーが提供する関数でもありません。しかし本書では使えるようにしました。
print("N");
よく似た関数 show も本書で使えます。print はその引数をフラット・テキストとして表示しますが、show はプログラムでそれが見えるように表示します。このため、値のタイプについてより多くの情報が得られます。例えば、文字列値を show に与える時は引用符が付いたままです:
show("N");
ブラウザーが提供する標準環境にはポップアップ・ウィンドウを開く関数があといくつかあります。confirm を使うとユーザーに OK/Cancel と回答する質問を作ることができます。この関数はユーザーが 'OK' を押した場合は true を、'Cancel' を押した場合は false を返します。
show(confirm("Shall we, then?"));
prompt は '自由な' 回答ができる質問を作ることができます。最初の引数は質問で、2 番目の引数はユーザーが答えるテキストです。1 行分のテキストがウィンドウにタイプでき、関数はこれを文字列として返します。
show(prompt("Tell us everything you know.", "..."));
この環境でほとんど全ての引数に新しい値を与えることができます。これは便利なことですが、危険でもあります。print に値 8 を与えると、それ以上表示することができなくなります。幸運にもコンソールには大きな 'Reset' ボタンがあり、これを押すと環境は元の状態にリセットされます。
1 行プログラムはさほど興味深くはありません。プログラムに複数のステートメントを置くと、ステートメントは予想通り上から下に 1 度に 1 つづつ順番に実行されます。
var theNumber = Number(prompt("Pick a number", ""));
print("Your number is the square root of " +
(theNumber * theNumber));
関数 Number は値を数字に変換します。上記の場合は prompt の結果が文字列値なので必要です。似た関数に String と Boolean があり、値をそれぞれのタイプに変換します。
0 から 12 までの全ての偶数を表示するプログラムを考えてください。一つの方法としては:
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; はループの本体となるステートメントです。しかし数字も表示しなければならないので、ループ・ステートメントには複数のステートメントが必要です。中括弧 ({ と }) を使ってステートメントを ブロックにグループ化します。ブロックの外では、ブロックが 1 つのステートメントと見なされます。前の例では、ブロックを使って print 呼び出しと currentNumber を更新するステートメントの両方をループに含めました。
Ex. 2.2
これまでのテクニックを使って値 2^10 (2 の 10 乗) を計算して表示するプログラムを書いてください。2 * 2 * ... のような手っ取り早い方法でもかまいません。
これが厄介なら、偶数の例を思い出してください。プログラムは一つの処理を何度か行わなければなりません。while ループのカウンター変数が役立ちます。カウンターを表示する代わりに、プログラムは何かを 2 倍しなければなりません。この何かがもう一つの変数で、ここに結果の値が作られます。
これがどうなるかまだ分からなくても心配ありません。たとえ本章のテクニックを全て完璧に理解していても、それを特定の問題に適用するのは難しいでしょう。コードを読んで書いてみることが助けになります。この回答を検討して次の問題を解いてください。
var result = 1;
var counter = 0;
while (counter < 10) {
result = result * 2;
counter = counter + 1;
}
show(result);
カウンターも 1 から始めて <= 10 をチェックしますが、後で分かるように、0 からカウントを始めることに慣れたほうが良いでしょう。
あなたの回答が私のと全く同じである必要はありません。結果は同じはずです。しかし回答がかなり違っていても、必ず私の回答も理解してください。
Ex. 2.3
前の練習問題の回答に少し修正を加えて、三角形を描くことができます。'三角形を描く' とはテキストを '一見三角形に見えるように表示する' という意味です。
10 行表示してください。最初の行には '#' を 1 つ、次の行には 2 つ、という具合です。
どうやったら X 個の '#' を持つ文字列にできるでしょう? 一つの方法として、必要な時に '内部ループ'、つまりループに中のループ、を使うやり方です。前の繰り返しで使った文字列を再利用し、それに 1 文字加えるとより簡単になります。
var line = "";
var counter = 0;
while (counter < 10) {
line = line + "#";
print(line);
counter = counter + 1;
}
いくつかのステートメントの前にスペースが置かれていることにお気付きでしょう。これらは必須ではありません: コンピュータはスペース無しでもコードを受け付けます。事実、プログラム中での改行も任意です。1 つの長い行で書いてもかまいません。インデントの役目はコードの構造をブロックに分けて読み手に分かりやすくすることです。ブロックの中に別のブロックが展開するため、複雑なコードではブロックが何処で終わり次のブロックが何処から始まるかが分からなくなることがあります。行をインデントするのは、プログラムの内側のブロック見た目に解りやすくするためです。私はブロックの前にスペースを 2 つ置くのが好きですが、これは好みの問題です。
Opera 以外のブラウザーでは、プログラムをタイプするとコンソール内のフィールドに自動的にスペースが入ります。最初は気になりますが、コードをたくさん書いているうちにこれがかなりの時間の節約になることが分かります。Tab キーを押すと、カーソルの現在位置よりもさらにインデントされます。
JavaScript ではステートメントの後のセミコロンを省略できる場合と、それが無いと奇妙なことが起こる場合があります。いつセミコロンを省略しても安全かのルールは複雑で一概に言うことはできません。本書ではどんなセミコロンも省略していません。プログラムを書く際にはこれを強くお勧めします。
これまで見てきた while の使い方は同じパターンを示しています。まず 'counter' 変数が作られます。この変数はループの進行状況を監視します。while 自身がカウンターが限度に来たかをチェックします。そしてループ本体の終わりでカウンターは更新されます。
多くのループがこのパターンです。このため、JavaScript やこれに似た言語はより短くより分かりやすいフォームも提供しています:
for (var number = 0; number <= 12; number = number + 2)
show(number);
このプログラムは前の偶数を表示する例と全く同じ機能です。唯一の違いは、ループの '状態' に関係するステートメントが全て 1 行に収まっていることです。for の後の括弧内にはセミコロンが 2 つ必要です。最初のセミコロンの前の部分でループを 初期化 します。変数を定義することによってこれを行うのが普通です。2 番目の部分はループを続けるべきかを チェック する式です。最後の部分はループの状態を 更新 します。多くの場合、この方が while 構造よりも短く明快です。
これまで変数名でおかしな 大文字 の使い方をしてきました。これらの名前にスペースを使うことができない ― コンピューターが複数の変数と見なす ― ため、名前の選択は多かれ大体次の選択肢しかありません:
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 はよく間違って使ってしまう例です。
Ex. 2.4
前の 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-- です。
ループはプログラムの制御フローに影響を与えると言われます。ステートメントの実行順序を変えるからです。多くの場合、複数のステートメントをスキップするフローが使われます。
3 と 4 で割ることのできる 20 以下の数字を全て表示します。
for (var counter = 0; counter < 20; counter++) {
if (counter % 3 == 0 && counter % 4 == 0)
show(counter);
}
キーワード if とキーワード while とはそれほど異なりません: 与えられた条件 (括弧内) をチェックし、この条件に基づいてステートメントを実行します。しかし if は一度だけ実行します。この場合ステートメントの実行回数はゼロか 1 です。
モジュロ (%) 演算子を使うとある数字が別の数字で割り切れるかを簡単にテストすることができます。割り切れる場合、モジュロが返す除算の余りはゼロです。
0 から 20 までの数字を全て表示する場合で 4 で割り切れないものをを括弧で囲みたい場合、次のようになります:
for (var counter = 0; counter < 20; counter++) {
if (counter % 4 == 0)
print(counter);
if (counter % 4 != 0)
print("(" + counter + ")");
}
しかしプログラムは counter が 4 で割り切れるかを 2 回判断しなければなりません。else 部を if ステートメントの後に付けると同じ効果を得ることができます。else ステートメントは if の条件が false の場合にだけ実行されます。
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 ステートメントに飛びます。
Ex. 2.5
prompt を使って 2 + 2 の値を自分に問いかけるプログラムを書いてください。alert を使って、答えが "4" の場合は何か褒める言葉を、"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 キーワードを使うことができます。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);
この場合ループ本体は空です。コロン 1 つで空のステートメントになります。このループは変数 current が求める値になるまでインクリメントするだけです。break を使った例を示したかったために紹介しましたが、最初の例にも注意してください。
Ex. 2.6
前の問題の回答に 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 チェーンにブロックの本体とステートメント 1 つの本体があるのは私には少々バランスが取れていない感じがしますが、決めるのはあなたです。
別の回答もあります。間違いなくより素晴らしいのですが、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 は複雑で分かりづらいルールを使います。ここで詳しく説明するつもりはありませんが、多くの場合、値の 1 つを他の値のタイプに変えようとします。しかし 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 は全て false になります。
これら以外の値全てが true に変換されるということから、多くの場合に明示的な比較を除外することが可能になります。変数が文字列か null を含むと分かっている場合、そのチェックは非常に簡単です...
var maybeNull = null;
// ... mystery code that might put a string into maybeNull ...
if (maybeNull)
print("maybeNull has a value");
mystery code が maybeNull に値 "" を与える場合は例外です。空の文字列は false で何も表示されません。何をしようとしているかにもよりますが、これは 間違っています。このような場合は些細なミスを防ぐためにも明示的に === null または === false を加えるべきです。数字の値が 0 になるかもしれない場合も同様です。
前の例で 'mystery code' についての行を不審に思ったかもしれません。プログラムにテキストを含めたほうが良い場合がよくあります。プログラムに人間の言葉で説明を追加するのが最も一般的です。
// 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 は strawberry は数字ではないと言っています。値 NaN にどんな算術演算をしても結果は NaN になります。これが上の例で 5 を掛けても NaN になった理由です。また、NaN == NaN が false になることにも面食らうでしょう。値が NaN であるかは isNaN 関数でチェックすることができます。NaN はブール型に変換されると false になるもう一つの (最後の) 値です。
これら自動変換は非常に便利なのですが、同時に奇妙で間違いの元になりかねません。+ と * は共に算術演算子ですが、例では働きが全く異なります。私のコードでは + を非文字列に使うことがよくありますが、* と他の数値演算子は文字列値には使わないことにしています。数字を文字列に変換するのは常に可能で直接的ですが、文字列から数字への変換は上手くいかない場合があります (例の最後の行がそれです)。明示的に文字列を数字に変換するためには Number を使うことができ、NaN を得るリスクがあることは明らかです。
show(Number("5") * 5);
前にブール型演算子 && と || の話をした時、これらはブール型値を生むと述べましたが、飛躍し過ぎでした。これらの演算子をブール型値に適用すれば確かにブール型が返されます。しかし他の種類の値、値中の引数を返すような値にも適用できるのです。
|| が実際にすることは: まず左側の値を調べます。この値をブール型に変換して true の場合、この左側の値を返します。そうでない場合は右側の値を返します。引数がブール型の場合にこのことが正しいかどうか自分で調べてみてください。何故こうなるのでしょう? でも実際にこういう結果になります。次の例を見てください:
var input = prompt("What is your name?", "Kilgore Trout");
print("Well hello " + (input || "dear"));
ユーザーが名前を与えずに他の方法で 'Cancel' を押すか 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.");
翻訳元
最終更新: