序論

私たちは、自分自身の目的のためにシステムを作っていると思っています。私たちは自分自身のイメージでそれを作っていると信じています...しかし、コンピュータは実際には私たちのようではありません。それは、私たち自身の非常に限られた部分、つまり論理、秩序、規則、そして明瞭さに特化した部分の投影なのです。

エレン・ウルマン、『機械に近づく:テクノフィリアとその不満』
Illustration of a screwdriver next to a circuit board of about the same size

この本は、コンピュータに指示を与えることについて書かれています。コンピュータは今日ではドライバーと同じくらい普及していますが、ドライバーよりもはるかに複雑で、思い通りに動かすのは必ずしも容易ではありません。

もしあなたがコンピュータにさせたいタスクが、メールを表示したり、電卓のように振る舞ったりといった、一般的でよく理解されているものであれば、適切なアプリケーションを開いて作業に取り掛かることができます。しかし、独自性が高かったり、自由度が高いタスクの場合、適切なアプリケーションがないことがよくあります。

そこでプログラミングの出番となるかもしれません。プログラミングとは、プログラム、つまりコンピュータに何をすべきかを指示する一連の正確な命令、を作成する行為です。コンピュータは愚かで、融通の利かない獣なので、プログラミングは基本的に退屈でイライラするものです。

幸いなことに、その事実を乗り越え、愚かな機械が扱えるような考え方で考えることの厳密さを楽しむことさえできれば、プログラミングはやりがいのあるものになる可能性があります。それは、手作業では永遠にかかることを数秒で行うことを可能にします。それは、あなたのコンピュータツールにこれまでできなかったことをさせる方法です。その上、それはパズルを解いたり、抽象的に考えたりする素晴らしいゲームになります。

ほとんどのプログラミングはプログラミング言語を使って行われます。プログラミング言語とは、コンピュータに指示を与えるために人工的に作られた言語です。コンピュータとコミュニケーションをとるための最も効果的な方法として私たちが見つけたものが、私たちがお互いにコミュニケーションをとる方法から大きく借用しているのは興味深いことです。人間の言語と同様に、コンピュータ言語では、単語やフレーズを新しい方法で組み合わせることができ、これまでにない新しい概念を表現することが可能になります。

かつては、1980年代や1990年代のBASICやDOSのプロンプトのような言語ベースのインターフェースが、コンピュータと対話する主な方法でした。日常的なコンピュータの使用では、これらは大部分が視覚的なインターフェースに置き換えられています。視覚的なインターフェースは学習しやすいですが、自由度は低くなります。しかし、どこを探せばいいのかを知っていれば、言語はまだそこにあります。その一つであるJavaScriptは、すべての最新のウェブブラウザに組み込まれており、そのため、ほとんどすべてのデバイスで利用できます。

この本は、あなたがこの言語に十分に慣れて、それで役に立ち、面白いことができるようにすることを目指しています。

プログラミングについて

JavaScriptを説明するだけでなく、プログラミングの基本原則を紹介します。プログラミングは難しいことが分かります。基本的なルールはシンプルで明確ですが、これらのルールの上に構築されたプログラムは、独自のルールと複雑さを導入するほど複雑になる傾向があります。ある意味で、あなたは自分自身の迷路を構築しており、その中で簡単に迷子になる可能性があります。

この本を読んでいると、非常にイライラする時があるでしょう。プログラミングが初めての場合、消化すべき新しい資料がたくさんあります。これらの資料の多くは、さらに接続を行う必要があるような方法で組み合わせられます。

必要な努力をするのはあなた次第です。本書の内容を理解するのに苦労しているときは、自分の能力について性急に結論を出さないでください。あなたは大丈夫です。ただ、続ける必要があるだけです。休憩を取り、いくつかの資料を再読し、サンプルプログラムと演習を読み、理解していることを確認してください。学習は大変な作業ですが、あなたが学ぶことはすべてあなたのものであり、さらなる学習を容易にします。

行動が利益をもたらさなくなったら、情報を集めなさい。情報が利益をもたらさなくなったら、眠りなさい。

アーシュラ・K・ル・グイン、『闇の左手』

プログラムは多くのものです。それはプログラマーによって入力されたテキストであり、コンピュータを動作させる原動力であり、コンピュータのメモリ内のデータであり、同時に、このメモリ上で行われる動作を制御します。プログラムをなじみのあるオブジェクトと比較しようとするアナロジーは、不十分になりがちです。表面的には、プログラムを機械と比較するのが適切です。多くの別々の部品が関与する傾向があり、全体を動かすためには、これらの部品がどのように相互に接続し、全体の動作に貢献しているかを考慮する必要があります。

コンピュータは、これらの非物質的な機械のホストとして機能する物理的な機械です。コンピュータ自体は、愚かで単純なことしかできません。コンピュータが非常に役に立つ理由は、これらのことを信じられないほどの速さで実行するためです。プログラムは、これらの単純な行動を非常に多く、巧みに組み合わせて、非常に複雑なことを行うことができます。

プログラムは思考の構築物です。構築するのに費用はかからず、重さはなく、タイピングする手の下で簡単に成長します。しかし、プログラムが成長するにつれて、その複雑さも増します。プログラミングのスキルとは、プログラマーを混乱させないプログラムを構築するスキルです。最良のプログラムとは、理解しやすいままで、何か面白いことをするプログラムです。

一部のプログラマーは、この複雑さは、プログラムでよく理解されている少数のテクニックのみを使用することで最もよく管理できると考えています。彼らは、プログラムが持つべき形式を規定する厳格なルール(「ベストプラクティス」)を作成し、安全な小さなゾーン内に慎重に留まります。

これは退屈なだけでなく、効果がありません。新しい問題には、しばしば新しい解決策が必要です。プログラミングの分野は若く、まだ急速に発展しており、大きく異なるアプローチに対応できるほど多様です。プログラム設計には、多くのひどい間違いがあり、それらを理解するために、少なくとも一度はそれらを犯してみるべきです。良いプログラムがどのように見えるかについての感覚は、練習によって培われるものであり、ルールのリストから学ぶものではありません。

言語が重要な理由

初期の頃、コンピューティングの誕生時には、プログラミング言語はありませんでした。プログラムは次のようになりました

00110001 00000000 00000000
00110001 00000001 00000001
00110011 00000001 00000010
01010001 00001011 00000010
00100010 00000010 00001000
01000011 00000001 00000000
01000001 00000001 00000001
00010000 00000010 00000000
01100010 00000000 00000000

これは、1から10までの数を足し合わせて結果を出力するプログラムです。 `1 + 2 + ... + 10 = 55`。これは、単純な仮説的なマシンで実行できます。初期のコンピュータをプログラムするには、大きなスイッチの配列を正しい位置に設定するか、厚紙に穴を開けてコンピュータに供給する必要がありました。この手順がどれほど退屈でエラーが発生しやすかったか想像できるでしょう。単純なプログラムを書くだけでも、多くの賢さと規律が必要でした。複雑なプログラムはほとんど想像もつきませんでした。

もちろん、これらの難解なビット(1と0)のパターンを手動で入力することは、プログラマーに自分が強力な魔法使いであるという深い感覚を与えました。そして、それは仕事の満足度という点で何か価値のあるものでなければなりません。

前のプログラムの各行には、1つの命令が含まれています。英語で書くと次のようになります

  1. メモリ位置0に数値0を格納します。

  2. メモリ位置1に数値1を格納します。

  3. メモリ位置1の値をメモリ位置2に格納します。

  4. メモリ位置2の値から数値11を引きます。

  5. メモリ位置2の値が数値0の場合は、命令9に進みます。

  6. メモリ位置1の値をメモリ位置0に加算します。

  7. メモリ位置1の値に数値1を加算します。

  8. 命令3に進みます。

  9. メモリ位置0の値を出力します。

これはすでにビットの羅列よりも読みやすいですが、まだかなり分かりにくいです。命令とメモリ位置に数値の代わりに名前を使用すると、理解しやすくなります。

  Set “total” to 0.
  Set “count” to 1.
[loop]
  Set “compare” to “count”.
  Subtract 11 from “compare”.
  If “compare” is 0, continue at [end].
  Add “count” to “total”.
  Add 1 to “count”.
  Continue at [loop].
[end]
  Output “total”.

この時点でプログラムがどのように動作するかがわかりますか?最初の2行は、2つのメモリ位置に初期値を与えています。`total`は計算結果を累積するために使用され、`count`は現在見ている数値を追跡するために使用されます。`compare`を使用している行はおそらく最も混乱しやすいでしょう。プログラムは、実行を停止できるかどうかを判断するために、`count`が11に等しいかどうかを確認したいと考えています。私たちの仮説的なマシンは非常に原始的であるため、数値がゼロかどうかだけをテストし、それに基づいて決定を下すことができます。したがって、`compare`というラベルの付いたメモリ位置を使用して`count - 11`の値を計算し、その値に基づいて決定を下します。次の2行は、プログラムが`count`がまだ11ではないと判断するたびに、結果に`count`の値を追加し、`count`を1ずつ増やします。

同じプログラムをJavaScriptで記述すると次のようになります。

let total = 0, count = 1;
while (count <= 10) {
  total += count;
  count += 1;
}
console.log(total);
// → 55

このバージョンでは、さらにいくつかの改善が加えられています。最も重要なのは、プログラムがどのようにジャンプするのかを指定する必要がなくなったことです。`while`構文がそれを処理します。指定された条件が成立する限り、その下のブロック(中括弧で囲まれた部分)を実行し続けます。その条件は`count <= 10`で、「カウントが10以下」を意味します。一時的な値を作成してそれをゼロと比較する必要はもうありません。それは単に興味のない詳細でした。プログラミング言語の力の1つは、興味のない詳細を私たちのために処理できることです。

`while`構文が終了した後、プログラムの最後に`console.log`操作を使用して結果を出力します。

最後に、範囲内の数値のコレクションを作成し、数値のコレクションの合計を計算する便利な操作`range`と`sum`が利用できる場合、プログラムは次のようになります。

console.log(sum(range(1, 10)));
// → 55

この話の教訓は、同じプログラムを長くても短くても、読みにくくても読みやすくても表現できるということです。プログラムの最初のバージョンは非常にわかりにくいものでしたが、最後のバージョンはほとんど英語です。1から10までの数値の`range`の`sum`を`log`に出力します。(`sum`や`range`のような操作を定義する方法は後の章で説明します。)

優れたプログラミング言語は、プログラマーがコンピューターが実行する必要があるアクションをより高いレベルで記述できるようにすることで、プログラマーを支援します。詳細を省略し、便利なビルディングブロック(`while`や`console.log`など)を提供し、独自のビルディングブロック(`sum`や`range`など)を定義できるようにし、それらのブロックを簡単に組み合わせることができるようにします。

JavaScriptとは何ですか?

JavaScriptは、Netscape NavigatorブラウザのWebページにプログラムを追加する方法として1995年に導入されました。それ以来、この言語は他のすべての主要なグラフィカルWebブラウザで採用されています。JavaScriptは、あらゆるアクションに対してページをリロードすることなく直接操作できる最新のWebアプリケーションを可能にしました。JavaScriptは、従来のWebサイトでも、さまざまな形式のインタラクティビティと巧妙さを提供するために使用されています。

JavaScriptは、Javaという名前のプログラミング言語とはほとんど関係がないことに注意することが重要です。似たような名前は、適切な判断ではなく、マーケティング上の考慮事項から着想を得たものです。JavaScriptが導入された当時、Java言語は大々的に販売され、人気が高まっていました。誰かがこの成功に乗じるのは良い考えだと考えたのです。今ではその名前に悩まされています。

Netscape以外での採用後、JavaScript言語がどのように動作すべきかを記述した標準ドキュメントが作成され、JavaScriptをサポートすると主張するさまざまなソフトウェアが実際に同じ言語を提供していることを確認できるようにしました。これは、標準化を実施したEcma International組織にちなんで、ECMAScript標準と呼ばれています。実際には、ECMAScriptとJavaScriptという用語は同じ意味で使用できます。どちらも同じ言語の2つの名前です。

JavaScriptについて*ひどい*ことを言う人がいます。これらのことの多くは真実です。初めてJavaScriptで何かを書く必要があったとき、私はすぐにそれを軽蔑するようになりました。入力したほとんどすべてを受け入れますが、私が意図したものとはまったく異なる方法で解釈します。もちろん、これは私が何をしているのかわからなかったことと大いに関係がありましたが、ここには本当の問題があります。JavaScriptは、それが許可するものにおいて途方もなくリベラルです。この設計の背後にある考え方は、初心者がJavaScriptでプログラミングしやすくなるということでした。実際には、システムが問題を指摘しないため、プログラムの問題を見つけるのが難しくなります。

しかし、この柔軟性には利点もあります。より厳格な言語では不可能なテクニックのための余地を残し、快適で非公式なプログラミングスタイルを実現します。言語を正しく学習し、しばらくの間それで作業した後、私は実際にJavaScriptを*好き*になりました。

JavaScriptにはいくつかのバージョンがありました。ECMAScriptバージョン3は、JavaScriptが支配的な地位に上り詰めた2000年から2010年頃にかけて広くサポートされていたバージョンです。この間、言語にいくつかの抜本的な改善と拡張を計画した意欲的なバージョン4の作業が進行中でした。広く使用されている生きた言語をこのように根本的に変更することは、政治的に難しいことが判明し、バージョン4の作業は2008年に放棄されました。議論の余地のない改善のみを行った、はるかに意欲的でないバージョン5は2009年にリリースされました。2015年には、バージョン4で計画されていたアイデアの一部を含むメジャーアップデートであるバージョン6がリリースされました。それ以来、毎年新しい小さなアップデートが行われています。

JavaScriptが進化しているということは、ブラウザが常に追いつく必要があることを意味します。古いブラウザを使用している場合、すべての機能がサポートされていない可能性があります。言語設計者は、既存のプログラムを壊す可能性のある変更を加えないように注意しているため、新しいブラウザでも古いプログラムを実行できます。この本では、2024年バージョンのJavaScriptを使用しています。

Webブラウザは、JavaScriptが使用される唯一のプラットフォームではありません。MongoDBやCouchDBなどの一部のデータベースは、スクリプト言語およびクエリ言語としてJavaScriptを使用しています。デスクトップおよびサーバープログラミング用のいくつかのプラットフォーム、特にNode.jsプロジェクト(第20章の主題)は、ブラウザの外部でJavaScriptをプログラミングするための環境を提供しています。

コードとその使用方法

*コード*は、プログラムを構成するテキストです。この本のほとんどの章には、かなりの量のコードが含まれています。コードを読んでコードを書くことは、プログラミングを学ぶ上で不可欠な部分だと私は信じています。例をざっと見て終わりにするのではなく、注意深く読んで理解するようにしてください。最初は遅くて混乱するかもしれませんが、すぐに慣れることを約束します。演習についても同様です。実際に動作するソリューションを作成するまで、理解したと思い込まないでください。

実際のJavaScriptインタプリタで演習の解答を試してみることをお勧めします。そうすれば、自分がやっていることがうまくいっているかどうかについてのフィードバックがすぐに得られ、実験して演習の先を行きたいという気持ちになることを願っています。

ブラウザでこの本を読んでいるときは、すべてのサンプルプログラムをクリックして編集(および実行)できます。

この本で定義されているプログラムを本のWebサイト以外で実行するには、注意が必要です。多くの例は単独で機能し、あらゆるJavaScript環境で動作するはずです。ただし、後の章のコードは多くの場合、特定の環境(ブラウザまたはNode.js)用に記述されており、そこでしか実行できません。さらに、多くの章ではより大きなプログラムが定義されており、それらに表示されるコードの断片は互いに、または外部ファイルに依存しています。Webサイトのサンドボックスには、特定の章のコードを実行するために必要なすべてのスクリプトとデータファイルを含むZIPファイルへのリンクが用意されています。

本書の概要

この本は、大きく分けて3つのパートで構成されています。最初の12章では、JavaScript言語について説明します。次の7つの章は、WebブラウザとJavaScriptを使用してそれらをプログラミングする方法についてです。最後に、2つの章が、JavaScriptをプログラミングするための別の環境であるNode.jsに充てられています。本書には、実際のプログラミングを味わってもらうために、より大きなサンプルプログラムについて説明する5つの*プロジェクト章*があります。

本書の言語部分は、JavaScript言語の基本構造を紹介する4つの章から始まります。これらの章では、制御構造(この導入部で見た`while`単語など)、関数(独自のビルディングブロックの作成)、およびデータ構造について説明します。これらを理解した後、基本的なプログラムを作成できるようになります。次に、第5章第6章では、関数とオブジェクトを使用してより*抽象的な*コードを記述し、複雑さを制御するためのテクニックを紹介します。

粗雑な配達ロボットを構築する最初のプロジェクト章の後、本書の言語部分は、エラー処理とバグ修正正規表現(テキストを操作するための重要なツール)、モジュール性(複雑さに対するもう1つの防御策)、および非同期プログラミング(時間がかかるイベントの処理)に関する章に進みます。プログラミング言語を実装する2番目のプロジェクト章で、本書の最初の部分が締めくくられます。

本書の2番目の部分である第13章から第19章では、ブラウザJavaScriptがアクセスできるツールについて説明します。画面にものを表示する方法(第14章第17章)、ユーザー入力に応答する方法(第15章)、ネットワーク経由で通信する方法(第18章)を学びます。この部分にも、プラットフォームゲームピクセルペイントプログラムを構築するという2つのプロジェクト章があります。

第20章ではNode.jsについて説明し、第21章ではそのツールを使用して小さなWebサイトを構築します。

表記規則

この本では、`monospaced`フォントで書かれたテキストは、プログラムの要素を表します。これらは自己完結型の断片である場合と、単に近くのプログラムの一部を参照する場合があります。プログラム(すでにいくつか見てきました)は次のように記述されます。

function factorial(n) {
  if (n == 0) {
    return 1;
  } else {
    return factorial(n - 1) * n;
  }
}

プログラムの出力を示すために、期待される出力がその後に記述される場合があります。その際は、出力の前にスラッシュ2つと矢印(`// ->`)を付けます。

console.log(factorial(8));
// → 40320

頑張ってください!