値、型、演算子
マシンの表面下で、プログラムは動いている。難なく拡張したり縮小したりする。素晴らしい調和の中で、電子は散乱し、再編成される。モニター上の形は、水面に広がる波紋に過ぎない。本質は目に見えないまま、下に留まっている。

コンピュータの世界には、データしか存在しない。データを読み、データを変更し、新しいデータを作成することができる。しかし、データではないものは言及できない。これらのデータはすべて、長いビット列として保存され、根本的には同じものである。
ビットとは、2つの値を持つあらゆるもので、通常は0と1で表される。コンピュータ内部では、高電荷または低電荷、強い信号または弱い信号、CD表面の光沢のある点または鈍い点など、さまざまな形で存在する。個別の情報はすべて、0と1の列に還元できるため、ビットで表現できる。
たとえば、数字の13をビットで表現できる。これは10進数と同じように機能するが、10個の異なる数字ではなく、2つしかない。それぞれの重みは、右から左へ2倍ずつ増加する。数字の13を構成するビットを、下に桁の重みを示して表す。
0 0 0 0 1 1 0 1 128 64 32 16 8 4 2 1
これは2進数の00001101である。0以外の数字は8、4、1を表し、合計すると13になる。
値
ビットの海、ビットの海原を想像してほしい。典型的な現代のコンピュータは、揮発性データストレージ(ワーキングメモリ)に1000億ビット以上の容量を持つ。不揮発性ストレージ(ハードディスクなど)は、さらに数桁大きい容量を持つ傾向がある。
迷子にならずにこのような量のビットを扱うために、情報を表すチャンクに分割する。JavaScript環境では、これらのチャンクは*値*と呼ばれる。すべての値はビットで構成されているが、それぞれ異なる役割を果たす。すべての値には、その役割を決定する型がある。数値の値、テキストの値、関数の値などがある。
値を作成するには、その名前を呼び出すだけでよい。これは便利だ。値のための材料を集めたり、お金を払ったりする必要はない。ただ呼び出すだけで、*ヒュッ*と手に入る。もちろん、値は実際には何もないところから生まれるわけではない。それぞれをどこかに保存する必要があり、同時に膨大な数の値を使用したい場合は、コンピュータのメモリが不足する可能性がある。幸いなことに、これはすべてを同時に必要とする場合にのみ問題となる。値が不要になるとすぐに消滅し、ビットは次の世代の値のための材料としてリサイクルされる。
この章の残りの部分では、JavaScriptプログラムの原子要素、つまり単純な値の型と、そのような値に作用する演算子について紹介する。
数値
*数値*型の値は、当然のことながら数値である。JavaScriptプログラムでは、次のように記述される。
13
これをプログラムで使用すると、数値13のビットパターンがコンピュータのメモリ内に生成される。
JavaScriptは、単一の数値を格納するために、64ビットの固定ビット数を使用する。64ビットで作成できるパターンは限られているため、表現できる異なる数値の数も制限される。*N*桁の10進数では、10の*N*乗個の数を表現できる。同様に、64個の2進数では、2の64乗個の異なる数を表現できる。これは約1800京(18の後に0が18個続く)である。これは非常に大きな数である。
かつてコンピュータのメモリははるかに小さく、人々は数値を表すために8ビットまたは16ビットのグループを使用する傾向があった。このような小さな数値は、簡単に*オーバーフロー*してしまう可能性があった。つまり、指定されたビット数に収まらない数値になってしまうのだ。今日では、ポケットに入るコンピュータでさえ、十分なメモリを搭載しているため、64ビットのチャンクを自由に使用できる。オーバーフローを心配する必要があるのは、本当に天文学的な数字を扱う場合のみである。
ただし、1800京未満のすべての整数がJavaScriptの数値に収まるわけではない。これらのビットは負の数も格納するため、1ビットは数値の符号を示す。より大きな問題は、整数ではない数を表現することである。これを行うために、一部のビットは小数点の位置を格納するために使用される。実際に格納できる最大の整数は、約9000兆(0が15個)の範囲である。これはまだ非常に大きな数である。
9.81
非常に大きい数または非常に小さい数の場合、*e*(指数)の後に数値の指数を追加することで、科学表記法を使用することもできる。
2.998e8
これは2.998 × 10の8乗 = 2億9980万である。
前述の9000兆よりも小さい整数(整数とも呼ばれる)を使用した計算は、常に正確であることが保証されている。残念ながら、小数を使用した計算は、一般的に正確ではない。π(円周率)を有限の桁数で正確に表現できないのと同じように、多くの数値は64ビットしか格納できない場合、精度が低下する。これは残念なことだが、特定の状況でのみ実際的な問題を引き起こす。重要なのは、このことを認識し、小数のデジタル数値を正確な値ではなく、近似値として扱うことである。
算術演算
数値を使用して行う主なことは、算術演算である。加算や乗算などの算術演算は、2つの数値を受け取り、それらから新しい数値を生成する。JavaScriptでは、次のようになる。
100 + 4 * 11
+
記号と*
記号は、*演算子*と呼ばれる。前者は加算を表し、後者は乗算を表す。2つの値の間に演算子を配置すると、それらの値に演算子が適用され、新しい値が生成される。
この例は、「4と100を加算し、その結果に11を乗算する」という意味だろうか、それとも乗算は加算の前に行われるのだろうか?ご想像のとおり、乗算が先に行われる。数学と同様に、加算をかっこで囲むことで、これを変更できる。
(100 + 4) * 11
減算には、`-`演算子がある。除算は`/`演算子で行うことができる。
演算子が括弧なしで一緒に現れる場合、それらが適用される順序は、演算子の*優先順位*によって決定される。この例は、乗算が加算よりも先に行われることを示している。`/`演算子は`*`と同じ優先順位を持つ。同様に、`+`と`-`は同じ優先順位を持つ。同じ優先順位を持つ複数の演算子が隣り合って現れる場合、例えば`1 - 2 + 1`のように、それらは左から右に適用される:`(1 - 2) + 1`。
これらの優先順位の規則については、あまり心配する必要はない。疑問がある場合は、括弧を追加すればよい。
もう1つ、すぐに認識できないかもしれない算術演算子がある。`%`記号は、*剰余*演算を表すために使用される。`X % Y`は、`X`を`Y`で割った余りである。例えば、`314 % 100`は`14`を生成し、`144 % 12`は`0`を与える。剰余演算子の優先順位は、乗算および除算と同じである。この演算子は、*モジュロ*と呼ばれることも多い。
特別な数値
JavaScriptには、数値と見なされるが、通常の数のようには動作しない3つの特別な値がある。最初の2つは、正と負の無限大を表す`Infinity`と`-Infinity`である。`Infinity - 1`は`Infinity`のままである。ただし、無限大に基づく計算を過信しすぎてはいけない。数学的に健全ではなく、すぐに次の特別な数値である`NaN`につながる。
`NaN`は「数値ではない」を表すが、*数値*型の値である。この結果は、例えば`0 / 0`(ゼロ割るゼロ)、`Infinity - Infinity`、またはその他の意味のある結果が得られない数値演算を実行しようとした場合に得られる。
文字列
次の基本データ型は文字列です。文字列はテキストを表すために使用されます。文字列は、その内容を引用符で囲むことで記述されます。
`Down on the sea` "Lie on the ocean" 'Float on the ocean'
文字列をマークするには、一重引用符、二重引用符、またはバッククォートを使用できます。ただし、文字列の開始と終了の引用符が一致している必要があります。
引用符の間にはほとんど何でも入れることができ、JavaScriptはそれを文字列値にします。ただし、扱いにくい文字がいくつかあります。引用符の中に引用符を入れると、文字列の終わりと見なされるため、難しいことが想像できます。改行(Enterキーを押したときに得られる文字)は、文字列がバッククォート(`
)で囲まれている場合にのみ含めることができます。
文字列にそのような文字を含めることができるように、次の表記法が使用されます。引用符で囲まれたテキスト内のバックスラッシュ(\
)は、その後の文字が特別な意味を持つことを示します。これは、文字をエスケープするといいます。バックスラッシュが前に付いた引用符は、文字列を終了させずに、文字列の一部になります。バックスラッシュの後にn
文字が出現すると、改行として解釈されます。同様に、バックスラッシュの後のt
はタブ文字を意味します。次の文字列を考えてみましょう。
"This is the first line\nAnd this is the second"
This is the first line And this is the second
もちろん、文字列内のバックスラッシュを特別なコードではなく、単なるバックスラッシュとして扱いたい場合があります。2つのバックスラッシュが連続している場合、それらは一緒に折りたたまれ、結果の文字列値には1つだけが残ります。このようにして、文字列「*改行文字は"\n"
のように記述されます。*」は次のように表現できます。
"A newline character is written like \"\\n\"."
文字列も、コンピューター内部に存在できるように、一連のビットとしてモデル化する必要があります。JavaScriptがこれを行う方法は、Unicode標準に基づいています。この標準は、ギリシャ語、アラビア語、日本語、アルメニア語などの文字を含む、必要なほぼすべての文字に番号を割り当てます。すべての文字に番号があれば、文字列は一連の番号で記述できます。そして、それがJavaScriptが行うことです。
ただし、複雑な点があります。JavaScriptの表現では、文字列要素ごとに16ビットを使用しており、最大216個の異なる文字を記述できます。しかし、Unicodeはそれよりも多くの文字を定義しています。現時点では約2倍です。そのため、多くの絵文字など、一部の文字はJavaScriptの文字列で2つの「文字位置」を占めます。第5章でこれに戻ります。
文字列は、除算、乗算、または減算できません。+
演算子は、加算ではなく、連結、つまり2つの文字列を結合するために使用できます。次の行は、文字列"concatenate"
を生成します。
"con" + "cat" + "e" + "nate"
文字列値には、文字列に対する他の操作を実行するために使用できる多くの関連関数(メソッド)があります。第4章でこれらについて詳しく説明します。
一重引用符または二重引用符で記述された文字列の動作はほとんど同じです。唯一の違いは、文字列内でエスケープする必要がある引用符の種類です。バッククォートで囲まれた文字列は、通常テンプレートリテラルと呼ばれ、さらにいくつかのことができます。複数行にまたがること以外にも、他の値を埋め込むことができます。
`half of 100 is ${100 / 2}`
テンプレートリテラルで${}
内に何かを記述すると、その結果が計算され、文字列に変換され、その位置に含まれます。この例では、文字列"half of 100 is 50"
が生成されます。
単項演算子
すべての演算子が記号であるわけではありません。単語として記述されるものもあります。1つの例は、指定した値の型を示す文字列値を生成するtypeof
演算子です。
console.log(typeof 4.5) // → number console.log(typeof "x") // → string
サンプルコードでは、console.log
を使用して、何かの評価結果を確認したいことを示します。(詳細については、次の章で説明します。)
この章でこれまでに示した他の演算子はすべて2つの値に対して演算を行いましたが、typeof
は1つだけを取ります。2つの値を使用する演算子は二項演算子と呼ばれ、1つを取る演算子は単項演算子と呼ばれます。マイナス演算子(-
)は、二項演算子と単項演算子の両方として使用できます。
console.log(- (10 - 2)) // → -8
ブール値
「はい」と「いいえ」、または「オン」と「オフ」のように、2つの可能性のみを区別する値を持つと便利なことがよくあります。この目的のために、JavaScriptにはブール型があり、trueとfalseの2つの値のみを持ち、これらの単語として記述されます。
比較
console.log(3 > 2) // → true console.log(3 < 2) // → false
>
記号と<
記号は、それぞれ「より大きい」と「より小さい」の従来の記号です。これらは二項演算子です。これらを適用すると、この場合にそれらが真であるかどうかを示すブール値が返されます。
console.log("Aardvark" < "Zoroaster") // → true
文字列の順序付け方法は、おおよそアルファベット順ですが、辞書に表示されるものとは実際には異なります。大文字は常に小文字よりも「小さい」ため、"Z" < "a"
となり、英字以外の文字(!、-など)も順序に含まれます。文字列を比較する場合、JavaScriptは文字を左から右に見て、Unicodeコードを1つずつ比較します。
他の同様の演算子には、>=
(以上)、<=
(以下)、==
(等しい)、および!=
(等しくない)があります。
console.log("Garnet" != "Ruby") // → true console.log("Pearl" == "Amethyst") // → false
JavaScriptには、それ自体と等しくない値が1つだけあります。それはNaN
(「数値ではない」)です。
console.log(NaN == NaN)
// → false
NaN
は無意味な計算の結果を示すことになっており、そのため、他の無意味な計算の結果とは等しくなりませ*ん*。
論理演算子
ブール値自体に適用できる操作もいくつかあります。JavaScriptは、and、or、notの3つの論理演算子をサポートしています。これらは、ブール値について「推論」するために使用できます。
&&
演算子は論理積を表します。これは二項演算子であり、指定された両方の値がtrueの場合にのみ、その結果はtrueになります。
console.log(true && false) // → false console.log(true && true) // → true
||
演算子は論理和を示します。指定されたいずれかの値がtrueの場合にtrueを生成します。
console.log(false || true) // → true console.log(false || false) // → false
notは感嘆符(!
)として記述されます。これは、指定された値を反転させる単項演算子です。!true
はfalse
を生成し、!false
はtrue
を生成します。
これらのブール演算子と算術演算子や他の演算子を混在させる場合、括弧が必要なタイミングは必ずしも明確ではありません。実際には、これまでに見てきた演算子のうち、||
の優先順位が最も低く、次に&&
、次に比較演算子(>
、==
など)、そして残りの演算子が続くことを知っていれば、通常は問題ありません。この順序は、次のような典型的な式で、できるだけ少ない括弧が必要になるように選択されています。
1 + 1 == 2 && 10 * 10 > 50
最後に紹介する論理演算子は、単項でも二項でもなく、3つの値を操作する*三項*です。これは、疑問符とコロンを使用して次のように記述されます。
console.log(true ? 1 : 2); // → 1 console.log(false ? 1 : 2); // → 2
これは、*条件*演算子(または、言語で唯一のそのような演算子であるため、単に*三項演算子*と呼ばれることもあります)と呼ばれます。演算子は、疑問符の左側の値を使用して、他の2つの値のどちらを「選択」するかを決定します。a ? b : c
と記述すると、a
がtrueの場合は結果はb
になり、そうでない場合はc
になります。
空の値
null
とundefined
の2つの特別な値があり、これらは*意味のある*値がないことを示すために使用されます。それら自体は値ですが、情報を持ちません。
言語の多くの操作では、意味のある値が生成されない場合、*何らかの*値を生成する必要があるため、単にundefined
が生成されます。
undefined
とnull
の意味の違いは、JavaScriptの設計上の偶然であり、ほとんどの場合問題になりません。これらの値を実際に気にする必要がある場合は、ほとんど同じものとして扱うことをお勧めします。
自動型変換
はじめにで、JavaScriptは、奇妙なことを行うプログラムであっても、指定されたほとんどすべてのプログラムを受け入れるためにあらゆる努力を払うと述べました。これは、次の式でうまく示されています。
console.log(8 * null) // → 0 console.log("5" - 1) // → 4 console.log("5" + 1) // → 51 console.log("five" * 2) // → NaN console.log(false == 0) // → true
JavaScriptでは、演算子が「間違った」型の値に適用された場合、JavaScriptは暗黙的にその値を必要な型に変換します。この変換は、多くの場合、意図しない、または予期しないルールセットに基づいて行われます。これは型強制と呼ばれます。最初の式では`null`が`0`に変換され、2番目の式では`"5"`が`5`(文字列から数値)に変換されます。しかし、3番目の式では、`+`は数値の加算を行う前に文字列の連結を試みるため、`1`は`"1"`(数値から文字列)に変換されます。
数値に明確に対応付けられないもの(`"five"`や`undefined`など)が数値に変換される場合、値`NaN`(Not a Number)が返されます。`NaN`に対するさらなる算術演算は`NaN`を生成し続けるため、予期しない場所で`NaN`が発生した場合は、意図しない型変換を探してください。
`==`演算子を使用して同じ型の値を比較する場合、結果は予測しやすいです。`NaN`の場合を除き、両方の値が同じ場合は`true`が返されます。しかし、型が異なる場合、JavaScriptは複雑で混乱しやすいルールセットを使用して、どのように処理するかを決定します。ほとんどの場合、一方の値をもう一方の値の型に変換しようとします。ただし、演算子の両側に`null`または`undefined`がある場合、両側が`null`または`undefined`のいずれかである場合にのみ`true`が生成されます。
console.log(null == undefined); // → true console.log(null == 0); // → false
この動作はしばしば便利です。値が`null`または`undefined`ではなく、実際の値を持っているかどうかをテストする場合、`==`または`!=`演算子を使用して`null`と比較できます。
何かが正確に値`false`を参照しているかどうかをテストしたい場合はどうでしょうか?`0 == false`や`"" == false`のような式も、自動型変換のために`true`になります。型変換を発生させたくない場合は、2つの追加の演算子があります:`===`と`!==`です。最初の演算子は、値がもう一方の値と*厳密に*等しいかどうかをテストし、2番目の演算子は厳密に等しくないかどうかをテストします。したがって、`"" === false`は、期待どおりに`false`になります。
予期しない型変換によって問題が発生するのを防ぐために、3文字の比較演算子を積極的に使用することをお勧めします。ただし、両側の型が同じであることが確実な場合は、短い演算子を使用しても問題ありません。
論理演算子の短絡評価
論理演算子`&&`と`||`は、異なる型の値を独特の方法で処理します。それらは、何をすべきかを決定するために、左側の値をブール型に変換しますが、演算子と変換の結果に応じて、*元の*左側の値または右側の値のいずれかを返します。
たとえば、`||`演算子は、左側の値が`true`に変換できる場合はその値を返し、そうでない場合は右側の値を返します。これは、値がブール値の場合に期待される効果をもたらし、他の型の値に対しても同様の動作をします。
console.log(null || "user") // → user console.log("Agnes" || "user") // → Agnes
この機能を使用して、デフォルト値にフォールバックすることができます。空である可能性のある値がある場合、その後に`||`と置換値を配置できます。初期値が`false`に変換できる場合、代わりに置換値が取得されます。文字列と数値をブール値に変換するルールでは、`0`、`NaN`、および空の文字列(`""`)は`false`としてカウントされ、他のすべての値は`true`としてカウントされます。つまり、`0 || -1`は`-1`を生成し、`"" || "!?"`は`"!?"`を生成します。
`??`演算子は`||`に似ていますが、左側の値が`null`または`undefined`の場合にのみ右側の値を返し、`false`に変換できる他の値の場合は返しません。多くの場合、これは`||`の動作よりも好ましいです。
console.log(0 || 100); // → 100 console.log(0 ?? 100); // → 0 console.log(null ?? 100); // → 100
`&&`演算子も同様に機能しますが、逆の方法で動作します。左側の値が`false`に変換されるものの場合、その値を返し、そうでない場合は右側の値を返します。
これら2つの演算子のもう1つの重要な特性は、右側の部分が必要な場合にのみ評価されることです。`true || X`の場合、`X`が何であっても—たとえそれが*恐ろしい*ことを行うプログラムの一部であっても—結果は`true`になり、`X`は評価されません。`false && X`についても同様で、これは`false`であり、`X`を無視します。これは*短絡評価*と呼ばれます。
条件演算子も同様に機能します。2番目と3番目の値のうち、選択された値のみが評価されます。
まとめ
この章では、JavaScriptの4つの型の値、数値、文字列、ブール値、および未定義値について調べました。このような値は、名前(`true`、`null`)または値(`13`、`"abc"`)を入力することによって作成されます。
演算子を使用して値を組み合わせたり変換したりできます。算術演算子(`+`、`-`、`*`、`/`、`%`)、文字列連結(`+`)、比較(`==`、`!=`、`===`、`!==`、`<`、`>`、`<=`、`>=`)、論理(`&&`、`||`、`??`)の二項演算子、およびいくつかの単項演算子(数値を否定する`-`、論理的に否定する`!`、値の型を見つける`typeof`)、3番目の値に基づいて2つの値のいずれかを選択する三項演算子(`?:`)について説明しました。
これで、JavaScriptを電卓として使用するには十分な情報が得られましたが、それ以上のことはできません。次の章では、これらの式を基本的なプログラムに結び付けることから始めます。