第3版が公開されました。こちらで読んでください!

第1章
値、型、演算子

機械の表面の下では、プログラムが動いている。何の努力もなく、それは拡大し、収縮する。完璧な調和の中で、電子は散乱し、再集合する。モニター上の形は、水面のさざ波にすぎない。本質は目に見えない底に留まる。

元馬大師、プログラミングの書

コンピューターの世界の中心には、データしか存在しない。データを読み込み、データを変更し、新しいデータを作成することはできるが、データでないものは存在しない。これらすべてのデータは、長いビット列として格納されており、根本的に同じである。

ビットとは、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であり、8 + 4 + 1 = 13となる。

ビットの海を想像してみよう。それらの海。典型的な最新のコンピューターには、揮発性データ記憶装置に300億ビット以上のビットがある。不揮発性記憶装置(ハードディスクなど)は、さらに数桁多い傾向がある。

The Ocean of Bits

これほど大量のビットを迷うことなく操作できるように、それらを情報のかたまりに分割できる。JavaScript環境では、これらの塊をと呼ぶ。すべての値はビットでできているものの、異なる役割を果たす。すべての値には、その役割を決定する型がある。JavaScriptには、数値、文字列、ブール値、オブジェクト、関数、未定義値という6つの基本的な値の型がある。

値を作成するには、その名前を呼び出すだけでよい。これは便利である。値のために建材を集めたり、それにお金を払ったりする必要はない。ただ呼び出すだけで、シューッと手に入る。もちろん、空気を集めて作られるわけではない。すべての値はどこかに保存する必要があり、同時に大量の値を使用したい場合、ビットを使い果たしてしまう可能性がある。幸いなことに、これは同時にすべてが必要な場合にのみ問題となる。値を使用しなくなるとすぐに、それは消散し、そのビットは次世代の値のための建材として再利用される。

この章では、JavaScriptプログラムの原子要素、つまり単純な値の型と、そのような値に作用できる演算子を導入する。

数値

数値型の値は、当然のことながら数値である。JavaScriptプログラムでは、次のように記述される。

13

これをプログラムで使用すると、コンピューターのメモリ内に13の数値に対するビットパターンが作成される。

JavaScriptは、1つの数値を格納するために、64ビットという固定数のビットを使用する。64ビットで作成できるパターンは限られているため、表現できる異なる数値の数は限られている。N桁の10進数の場合、表現できる数値の数は10Nである。同様に、64ビットの2進数では、264個の異なる数値を表すことができ、これは約18 quintillion(18の後に18個のゼロが付く)である。これは非常に多い。

コンピューターのメモリは以前ははるかに小さかったため、人々は8ビットまたは16ビットのグループを使用して数値を表すことが多かった。そのような小さな数値をオーバーフローさせることは簡単だった。つまり、与えられたビット数に収まらない数値になることである。今日では、パーソナルコンピューターにも十分なメモリがあるため、64ビットのチャンクを使用することができ、本当に天文学的な数値を扱う場合を除いて、オーバーフローについて心配する必要はない。

しかし、18 quintillion以下のすべての整数がJavaScriptの数値に収まるわけではない。これらのビットは負の数も格納するため、1つのビットは数値の符号を示す。より大きな問題は、非整数も表現しなければならないことである。これを行うために、いくつかのビットは小数点の位置を格納するために使用される。実際に格納できる最大の整数は、9 quadrillion(15個のゼロ)の範囲であり、それでも十分に大きい。

小数は、ドットを使用して記述する。

9.81

非常に大きくても小さくても、数値の指数に「e」(「exponent」の略)を追加することで、指数表記を使用することもできる。

2.998e8

これは2.998 × 108 = 299,800,000である。

前述の9 quadrillionより小さい整数(整数とも呼ばれる)を使用した計算は、常に正確であることが保証されている。残念ながら、小数を使用した計算は一般的に正確ではない。π(円周率)は有限個の10進数で正確に表現できないのと同様に、多くの数は、64ビットしか使用できない場合、精度を失う。これは残念だが、具体的な状況でのみ実用的な問題を引き起こす。重要なのは、それを認識し、小数のデジタル数値を近似値として扱い、正確な値として扱わないことである。

算術演算

数値で最も重要なことは算術演算である。加算や乗算などの算術演算は、2つの数値を取り、それらから新しい数値を生成する。JavaScriptでの記述方法は次のとおりである。

100 + 4 * 11

+*記号は演算子と呼ばれる。最初の記号は加算を表し、2番目の記号は乗算を表す。2つの値の間に演算子を置くことで、それらの値に適用し、新しい値を生成する。

この例は「4と100を加算し、その結果に11を乗算する」という意味なのか、それとも乗算が加算より先に実行されるのか?予想通り、乗算が先に実行される。しかし、数学と同様に、加算を括弧で囲むことでこれを変更できる。

(100 + 4) * 11

減算には-演算子があり、除算には/演算子を使用できる。

括弧がない状態で演算子が一緒に現れる場合、それらが適用される順序は、演算子の優先順位によって決定される。この例では、乗算が加算より先に実行されることが示されている。/演算子の優先順位は*と同じである。同様に、+-も同様である。1 - 2 + 1のように、同じ優先順位の複数の演算子が隣り合って現れる場合、それらは左から右に適用される:(1 - 2) + 1

これらの優先順位の規則は、心配する必要はない。疑わしい場合は、括弧を追加するだけでよい。

もう1つの算術演算子があり、すぐに認識できないかもしれない。%記号は剰余演算を表すために使用される。X % YXYで除算した剰余である。例えば、314 % 10014を生成し、144 % 120を生成する。剰余の優先順位は、乗算と除算と同じである。この演算子は、技術的には剰余の方が正確であるが、多くの場合モジュロと呼ばれる。

特殊な数値

JavaScriptには、数値と見なされるが、通常の数値のように動作しない3つの特殊な値がある。

最初の2つはInfinity-Infinityであり、正の無限大と負の無限大を表す。Infinity - 1は依然としてInfinityであり、以下同様である。無限大に基づく計算にはあまり頼らないこと。数学的に堅牢ではなく、すぐに次の特殊な数値であるNaNにつながる。

NaNは「数値ではない」という意味だが、数値型の値である。例えば、0 / 0(ゼロでゼロを除算)、Infinity - Infinity、またはその他の正確で意味のある結果が得られない多くの数値演算を試みると、この結果が得られる。

文字列

次の基本データ型は文字列である。文字列はテキストを表すために使用される。文字列の内容は引用符で囲んで記述する。

"Patch my boat with chewing gum"
'Monkeys wave goodbye'

文字列の先頭と末尾の引用符が一致していれば、単一引用符と二重引用符の両方を使用して文字列をマークできる。

引用符(クォーテーションマーク)で囲めば、ほとんど何でもJavaScriptの文字列値として扱うことができます。しかし、いくつか扱いにくい文字があります。引用符を引用符の中に含めるのが難しいことは想像できるでしょう。改行(Enterキーを押したときに生成される文字)も、引用符で囲むことはできません。文字列は1行に収まっていなければなりません。

このような文字を文字列に含めるために、以下の表記法が使用されます。引用符で囲まれたテキスト内でバックスラッシュ(\)が見つかった場合、その後の文字が特別な意味を持つことを示します。これは文字のエスケープと呼ばれます。バックスラッシュの前にある引用符は、文字列を終了するのではなく、文字列の一部となります。バックスラッシュの後に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\"."

文字列は除算、乗算、減算することはできませんが、+演算子は使用できます。これは加算ではなく、連結を行います—2つの文字列を繋ぎ合わせます。次の行は"concatenate"という文字列を生成します。

"con" + "cat" + "e" + "nate"

文字列を操作する方法は他にもありますが、第4章でメソッドについて説明する際に詳しく説明します。

単項演算子

すべての演算子が記号であるわけではありません。単語として記述されるものもあります。1つの例として、typeof演算子があります。これは、渡された値の型を表す文字列値を生成します。

console.log(typeof 4.5)
// → number
console.log(typeof "x")
// → string

例コードでは、何かを評価した結果を表示したいことを示すためにconsole.logを使用します。このようなコードを実行すると、生成された値が画面に表示されますが、表示方法は使用するJavaScript実行環境によって異なります。

これまで見てきた他の演算子はすべて2つの値を操作しましたが、typeofは1つの値しか受け取りません。2つの値を使用する演算子は二項演算子と呼ばれ、1つの値を受け取る演算子は単項演算子と呼ばれます。マイナス演算子は、二項演算子と単項演算子の両方として使用できます。

console.log(- (10 - 2))
// → -8

ブール値

多くの場合、「はい」と「いいえ」、または「オン」と「オフ」のように、2つの可能性を区別するだけの値が必要になります。そのため、JavaScriptにはブール型があり、trueとfalse(これらの単語として記述されます)の2つの値のみを持ちます。

比較

ブール値を生成する1つの方法を以下に示します。

console.log(3 > 2)
// → true
console.log(3 < 2)
// → false

><記号は、それぞれ「より大きい」と「より小さい」を表す従来の記号です。これらは二項演算子です。これらを適用すると、その場合に成立するかどうかを示すブール値が生成されます。

文字列も同様に比較できます。

console.log("Aardvark" < "Zoroaster")
// → true

文字列の順序付けは、ほぼアルファベット順です。大文字は常に小文字より「小さい」ため、"Z" < "a"はtrueであり、アルファベット以外の文字(!、-など)も順序に含まれています。実際の比較はUnicode標準に基づいています。この標準では、ギリシャ語、アラビア語、日本語、タミル語などの文字を含む、実質的に必要なすべての文字に番号を割り当てています。このような番号があると、文字列を数値のシーケンスとして表すことができるため、コンピューター内に文字列を保存するのに役立ちます。文字列を比較する場合、JavaScriptは左から右に文字列を調べ、文字の数字コードを1つずつ比較します。

その他にも、>=(以上)、<=(以下)、==(等しい)、!=(等しくない)などの同様の演算子があります。

console.log("Itchy" != "Scratchy")
// → true

JavaScriptには、それ自身と等しくない値が1つだけあり、それは「数値ではない」という意味のNaNです。

console.log(NaN == NaN)
// → false

NaNは、無意味な計算の結果を示すものとされており、そのため、他の無意味な計算の結果と等しくありません。

論理演算子

ブール値自体に適用できる演算もあります。JavaScriptは、andornotの3つの論理演算子をサポートしています。これらはブール値について「推論」するために使用できます。

&&演算子は論理andを表します。これは二項演算子であり、渡された両方の値がtrueの場合にのみtrueになります。

console.log(true && false)
// → false
console.log(true && true)
// → true

||演算子は論理orを表します。渡された値のいずれかがtrueの場合、trueになります。

console.log(false || true)
// → true
console.log(false || false)
// → false

Notは感嘆符(!)として記述されます。これは、渡された値を反転させる単項演算子です—!truefalseを生成し、!falsetrueを生成します。

これらのブール演算子を算術演算子やその他の演算子と組み合わせる場合、括弧が必要なタイミングは必ずしも明らかではありません。実際には、これまで見てきた演算子のうち、||が最も優先順位が低く、次に&&、次に比較演算子(>==など)、そして残りの演算子が続きます。この順序は、次の例のような典型的な式では、可能な限り少ない括弧で済むように選択されています。

1 + 1 == 2 && 10 * 10 > 50

最後に説明する論理演算子は、単項でも二項でもなく、3つの値を操作する三項演算子です。これは疑問符とコロンを使用して次のように記述されます。

console.log(true ? 1 : 2);
// → 1
console.log(false ? 1 : 2);
// → 2

これは条件演算子(または言語で唯一のそのような演算子であるため、単に三項演算子と呼ばれることもあります)と呼ばれます。疑問符の左側の値によって、他の2つの値のどちらが出力されるかが選択されます。trueの場合、中央の値が選択され、falseの場合、右側の値が出力されます。

未定義の値

nullundefinedという2つの特別な値があり、意味のある値がないことを示すために使用されます。それ自体が値ですが、情報は持ちません。

意味のある値を生成しない言語の多くの演算(後述)は、単に何らかの値を生成する必要があるため、undefinedを生成します。

undefinednullの意味の違いは、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はその値を必要とする型に静かに変換します。これは、多くの場合、期待どおりではないルールセットを使用します。これは型強制と呼ばれます。そのため、最初の式のnull0になり、2番目の式の"5"5になります(文字列から数値へ)。しかし、3番目の式では、+は数値の加算の前に文字列の連結を試みるため、1"1"に変換されます(数値から文字列へ)。

"five"undefinedなど、明らかに数値に対応しないものが数値に変換されると、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という値を参照しているかどうかをテストしたい場合はどうでしょうか?文字列と数値をブール値に変換するルールでは、0NaN、空文字列("")はfalseとしてカウントされ、他のすべての値はtrueとしてカウントされます。このため、0 == false"" == falseのような式もtrueになります。このような場合、自動型変換をまったく行いたくない場合は、===!==の2つの追加演算子があります。前者は値が正確に等しいかどうかをテストし、後者は正確に等しくないかどうかをテストします。そのため、"" === falseは予想どおりfalseになります。

予期しない型変換によって問題が発生するのを防ぐために、防御的に3文字の比較演算子を使用することをお勧めします。しかし、両側の型が同じであることが確実な場合は、短い演算子を使用しても問題ありません。

論理演算子の短絡評価

論理演算子&&||は、異なる型の値を特殊な方法で処理します。実行方法を決定するために、左側の値をブール型に変換しますが、演算子と変換結果に応じて、元の左側の値または右側の値を返します。

たとえば、||演算子は、左側の値をtrueに変換できる場合、左側の値を返し、そうでない場合は右側の値を返します。この変換はブール値で期待どおりに機能し、他の型の値についても同様の動作を行う必要があります。

console.log(null || "user")
// → user
console.log("Karl" || "user")
// → Karl

この機能により、||演算子をデフォルト値にフォールバックする方法として使用できます。左側に空の値を生成する可能性のある式を渡すと、その場合、右側の値が代替値として使用されます。

&&演算子は同様に機能しますが、逆です。左側の値がfalseに変換されるものの場合は、その値を返し、そうでない場合は右側の値を返します。

これらの2つの演算子のもう一つの重要な特性は、右側の式が必要な場合にのみ評価されることです。true || Xの場合、Xがどのようなものであっても(たとえひどいことをする式であっても)、結果はtrueになり、Xは決して評価されません。false && Xも同じで、falseになり、Xを無視します。これは短絡評価と呼ばれます。

条件演算子も同様の動作をします。最初の式は常に評価されますが、2番目または3番目の値、つまり選択されない値は評価されません。

概要

この章では、JavaScriptの4種類の値、数値、文字列、ブール値、およびundefined値について見てきました。

このような値は、名前(truenull)または値(13"abc")を入力することで作成されます。演算子を使用して値を組み合わせたり変換したりできます。算術(+-*/%)、文字列連結(+)、比較(==!====!==<><=>=)、論理(&&||)のための二項演算子、ならびにいくつかの単項演算子(数値を否定する-、論理的に否定する!、値の型を見つけるtypeof)と、3番目の値に基づいて2つの値のいずれかを選択する三項演算子(?:)を見ました。

これにより、JavaScriptをポケット電卓として使用するための十分な情報が得られますが、それ以上のことはできません。次の章では、これらの式を基本的なプログラムに結び付けることから始めます。