第4版が利用可能です。 こちらでお読みください!

はじめに

私たちは、自分たちの目的のためにシステムを作っていると考えています。私たちは、自分たちの姿を投影していると信じています... しかし、コンピュータは実際には私たちとは異なります。それは、私たち自身のほんの一部分、つまり論理、秩序、規則、そして明快さに特化した部分の投影なのです。

エレン・ウルマン, 機械に近い:テクノフィリアとその不満
Picture of a screwdriver and a circuit board

これはコンピュータに指示を与えることについての本です。コンピュータは今日、ドライバーと同じくらい一般的ですが、はるかに複雑で、コンピュータに自分の望むことをさせるのは必ずしも簡単ではありません。

もしあなたがコンピュータにさせたいことが、メールを見たり、電卓のように動作したりするような、一般的でよく理解されていることであれば、適切なアプリケーションを開いて作業を始めることができます。しかし、ユニークまたはオープンエンドなタスクの場合、おそらくアプリケーションは存在しないでしょう。

そこでプログラミングが登場するかもしれません。プログラミングとは、コンピュータに何をすべきかを指示する一連の正確な命令であるプログラムを構築する行為です。コンピュータは愚かで、融通の利かない動物であるため、プログラミングは基本的に退屈でイライラするものです。

幸いなことに、もしあなたがその事実を乗り越え、もしかしたら、愚かな機械が理解できる言葉で考える厳密さを楽しむことができれば、プログラミングはやりがいのあるものになるでしょう。手作業では永遠にかかるようなことを数秒で実行することができます。それは、あなたのコンピュータツールが以前にはできなかったことを実行できるようにする方法です。そして、抽象的な思考のための素晴らしい訓練になります。

ほとんどのプログラミングはプログラミング言語を使って行われます。プログラミング言語とは、コンピュータに指示を与えるために使用される人工的に構築された言語です。コンピュータと通信するための最も効果的な方法が、私たちがお互いに通信する方法に非常に依存しているというのは興味深いことです。人間の言語のように、コンピュータ言語も単語やフレーズを新しい方法で組み合わせることができ、常に新しい概念を表現することができます。

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

この本は、この言語に十分に慣れて、それを使って便利で面白いことができるようにすることを目的としています。

プログラミングについて

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. メモリ位置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 zero, 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の値を結果に加算し、プログラムがcountがまだ11ではないと判断するたびに、countを1ずつインクリメントします。

以下は同じプログラムをJavaScriptで記述したものです。

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

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

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

最後に、もし便利な操作であるrangesumが利用可能だった場合、プログラムがどのように見えるかを示します。それぞれ、範囲内の数のコレクションを作成し、数のコレクションの合計を計算します。

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

この話の教訓は、同じプログラムでも、長く記述することも、短く記述することも、読みにくい方法で記述することも、読みやすい方法で記述することもできるということです。最初のバージョンのプログラムは非常に分かりにくかったですが、最後のバージョンはほとんど英語のようです。「1から10までの数のrangesumlogする」(sumrangeのような操作をどのように定義するかは、後の章で説明します)。

優れたプログラミング言語は、コンピューターが行うべきアクションをより高いレベルで記述できるようにすることで、プログラマーを支援します。詳細を省略したり、便利な構成要素(whileconsole.logなど)を提供したり、独自の構成要素(sumrangeなど)を定義したり、それらの構成要素を簡単に組み合わせたりできるようにします。

JavaScriptとは何ですか?

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

JavaScriptは、Javaというプログラミング言語とはほとんど関係がないことに注意することが重要です。似たような名前は、優れた判断というよりは、マーケティング上の配慮から付けられたものです。JavaScriptが導入されたとき、Java言語は盛んに宣伝されており、人気が高まっていました。誰かが、この成功に乗っかろうとするのは良いアイデアだと思ったのです。今、私たちはその名前のままになっています。

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

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

ただし、この柔軟性には利点もあります。これにより、より厳格な言語では不可能な多くのテクニックのための余地が残されており、ご覧のとおり(たとえば、10章)、JavaScriptの欠点の一部を克服するために使用できます。言語を適切に学習し、しばらくの間使用した後、私は実際にJavaScriptを好きになりました。

JavaScriptにはいくつかのバージョンがあります。ECMAScriptバージョン3は、JavaScriptが優位性を獲得した時期、おおよそ2000年から2010年の間に広くサポートされていたバージョンでした。この間、言語に多くの抜本的な改善と拡張を計画した野心的なバージョン4の開発が進められていました。広く使用されている生きた言語をこのように抜本的に変更することは政治的に困難であることが判明し、バージョン4の開発は2008年に中止されました。その結果、2009年に登場したバージョン5は、あまり野心的ではなく、議論の余地のない改善をいくつか行っただけでした。その後、2015年にバージョン6が登場し、バージョン4で計画されていたアイデアの一部が含まれたメジャーアップデートが行われました。それ以降、毎年新しい小規模なアップデートが行われています。

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

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

コードと、その扱い方

コードとは、プログラムを構成するテキストのことです。本書のほとんどの章には、非常に多くのコードが含まれています。コードを読んだり、書いたりすることは、プログラミングを学ぶ上で不可欠な部分であると私は考えています。例をざっと見るだけでなく、注意深く読んで理解するようにしてください。最初は遅くて混乱するかもしれませんが、すぐに慣れると約束します。練習問題も同様です。実際に動作する解決策を書くまで、理解したと仮定しないでください。

実際のJavaScriptインタープリターで練習問題の解決策を試すことをお勧めします。そうすることで、自分のしていることが実際に機能しているかどうかについてすぐにフィードバックが得られ、練習問題を超えて実験したくなるでしょう。

ブラウザでこの本を読んでいる場合、例のプログラムをクリックすることで、編集(および実行)できます。

この本で定義されているプログラムを本のWebサイト以外で実行したい場合は、ある程度の注意が必要です。多くの例はそれ自体で完結しており、任意のJavaScript環境で動作するはずです。しかし、後の章のコードは、特定の環境(ブラウザまたはNode.js)向けに書かれていることが多く、そこでしか実行できません。さらに、多くの章ではより大きなプログラムを定義しており、それらに現れるコードは互いに、または外部ファイルに依存しています。Webサイトのサンドボックスには、特定の章のコードを実行するために必要なすべてのスクリプトとデータファイルを含むZipファイルへのリンクが用意されています。

本書の概要

この本は、おおよそ3つのパートで構成されています。最初の12章では、JavaScript言語について説明します。次の7章では、Webブラウザと、JavaScriptを使用してWebブラウザをプログラムする方法について説明します。最後に、2つの章は、JavaScriptをプログラミングするための別の環境であるNode.jsに費やされています。

本書全体を通して、実際のプログラミングを体験できるように、より大きなサンプルプログラムを解説するプロジェクトの章が5つあります。登場順に、配達ロボットプログラミング言語プラットフォームゲームピクセルペイントプログラム、そして動的なウェブサイトを構築していきます。

本書の言語に関する部分は、JavaScript言語の基本的な構造を紹介する4つの章から始まります。これらの章では、制御構造(この入門で見たwhileのような単語)、関数(独自の構成要素の作成)、データ構造について紹介します。これらの後、基本的なプログラムを書けるようになるでしょう。次に、5章6章では、関数とオブジェクトを使ってより抽象的なコードを書き、複雑さを制御するテクニックを紹介します。

最初のプロジェクトの章の後、本書の言語に関する部分は、エラー処理とバグ修正正規表現(テキストを扱う上で重要なツール)、モジュール性(複雑さに対するもう一つの防御策)、そして非同期プログラミング(時間がかかるイベントの処理)に関する章が続きます。2番目のプロジェクトの章で、本書の最初の部分が完結します。

第2部である13章から19章では、ブラウザのJavaScriptがアクセスできるツールについて解説します。画面への表示(14章17章)、ユーザー入力への応答(15章)、ネットワーク経由での通信(18章)について学びます。この部分にも2つのプロジェクトの章があります。

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

表記上の規則

本書では、等幅フォントで書かれたテキストは、プログラムの要素を表します。時にはそれらは独立した断片であり、時には近くのプログラムの一部を参照するだけです。(すでにいくつか見てきた)プログラムは、次のように書かれています。

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

プログラムが生成する出力を示すために、期待される出力が、前に2つのスラッシュと矢印を付けて、その後に書かれることがあります。

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

頑張ってください!