がみぶろ

#がみぶろ

@jumpei_ikegami

サイ本こと『JavaScript 第6版』全800ページを読破し、1万行のesaにまとめてわかった5つのこと

しがないラジオのgamiです。

JavaScript界隈では有名な、オライリーのサイ本こと『JavaScript 第6版』という鈍器、もとい書籍を読みました。

JavaScript 第6版

JavaScript 第6版

2012年に発行された、約800ページもある、かなり内容の多い本です。 僕は本を読むときにesaに要約しながら読み進めるのですが、サイ本のまとめesaは全体で「約1万行」という修行みたいな分量になっていました。

サイ本を要約しながらじっくりJavaScriptを学んだ人はこの世界にあまりいないと思うので、わかったことをまとめます。

読み始めたきっかけ

僕は約2年前に、富士通から、今働いているプレイドという会社に転職しました。 富士通ではCOBOL(!)とJavaしか書いていなかったので、Node.js+Vue.jsの会社に転職するための準備として、『JavaScript 第6版』を買った記憶があります。

今思えば、もっと軽い入門書もあったと思います。中二病だったのでしょう。

JavaScript 第6版』を読んでわかった5つのこと

サイ本を読んで、JavaScriptプログラミング言語としての立ち位置や面白さがわかりました。

JavaScriptを学ぶ」ことの多くは、「ブラウザの仕様を学ぶ」こと

サイ本は、大きく「コアJavaScript」と「クライアントサイドJavaScript」の2部に分かれています。「コアJavaScript」では、主にJavaScriptの文法について説明しています。型、演算子、文、関数、正規表現など、他のプログラミング言語の入門書でも必ず説明されるような内容です。

特徴的なのは、「コアJavaScript」よりも「クライアントサイドJavaScript」の方により多くの紙幅を割いている点です。他のプログラミング言語の入門書であれば、簡単にライブラリを紹介する章はあっても、言語自体の文法に関する説明よりも短く掲載される場合がほとんどでしょう。JavaScriptの場合は、「Webブラウザ」という切っても切り離せない巨大アプリケーション群があり、ほとんどの場合はその実行環境を前提として記述されます。そのため、「JavaScriptを学ぶ」ということの多くは、「ブラウザの仕様」や「DOMを含むWeb API群の標準仕様」を学ぶということなのだなあ、ということをサイ本を読んで実感しました。

例えば、ただJavaScriptで計算をしたいだけなら、別にWebページのHTMLをどのように操作できるかなど知らなくても何も困りません。ただし、JavaScriptを書きたい、学びたい、というモチベーションの多くは、Webのクライアントサイドに関わる以下のようなことです。

  • 動的にHTMLやCSSを変化させたい(DOMやCSSOMの制御)
  • ユーザーの操作に応じて処理を変えたい(イベント処理)
  • 外部サーバーと非同期で通信したい(Ajax
  • ブラウザ側にデータを保持して、IDやセッションを管理したい(Cookie、localStorage)

逆にクライアントサイドJavaScriptは、それを学ぶ過程で、HTMLやCSSの仕様に依存したAPIを学ぶことになります。なので、Webのクライアントサイドの技術について深く学びたい場合は、JavaScriptの学習をすることで、HTMLやCSSも含めたブラウザの仕様について深く理解できるようになると思います。

ちなみに、2007年に発行された一つ前の版である『JavaScript 第5版』の目次を『JavaScript 第6版』のものと比べると、ブラウザの機能の変遷がわかって非常に面白いです。

www.oreilly.co.jp

www.oreilly.co.jp

2007年の第5版では「Javaアプレット」、「Flash」、「XML」などの章がありますが、2012年の第6版ではそれらがすべて削除され、代わりに後述する「jQuery」や「HTML5 API」の章が追加されています。

クライアントサイドJavaScriptの爆発的変化

JavaScript 第6版』が出版されたのは、2012年の8月です。今が2018年の7月なので、たった6年前になります。ただし、この本に書かれている内容ですら、すでに一部の仕様が廃止されていました。

例えば、windowオブジェクトのメソッドとして本書で紹介されているshowModalDialog()は、MDNで調べると「この機能は削除されました。ウェブサイトやアプリケーションを修正してください。」と書かれています。

「ブラウザは後方互換性を大事にするので機能を削除できない」とよく耳にしますが、仕様の議論が不十分なままブラウザに実装された過去の機能については、廃止されているものもあるようです。

サイ本を読むとき、あまり聞いたことのない機能については、実際にブラウザのコンソールで本当に使えるのか試したり、MDNに記載があるかを調べたりしていました。少し古めのJavaScript本を読むときは、機能が廃止されている可能性を考慮しながら読んだ方が良さそうです。

なお、JavaScriptはES2015で以下のような新しいシンタックスがかなり追加されましたが、サイ本にはそれに関する以下のような記載はありません。

  • letconstによる変数宣言
  • アロー関数
  • class構文
  • 分割代入
  • importとexport

さらに、現代のクライアントサイドJavaScriptとは切っても切り離せない以下のような技術スタックには特に触れられていません。

フロントエンドの開発に求められるものの多様化とWeb技術の変化の速さを揶揄して「フロントエンド地獄」と呼ばれますが、サイ本もまた(少なくとも第6版の時点では)その地獄に囚われ古臭い本になりつつありました。

そのためサイ本は、「最新のJavaScript」ではなく、「時代を経ても変わらないJavaScriptのエッセンスや、すでに安定したWeb API」について学ぶための本として読んだ方がよいです。

「最新のJavaScript」については、出版されるかわからない『JavaScript 第7版』に期待しましょう。

ブラウザ間の差異から来る闇

JavaScriptという言語の特殊性として、その実装はブラウザベンダーに委ねられており、独自の方言が認められている点があります。もちろん、Webページを実装する開発者としては、1つのJavaScriptファイルが複数のブラウザで意図通りに動作することを期待します。ただし、歴史的経緯から来るブラウザ間の仕様の差異によって、その期待はしばしば裏切られてきたことが、サイ本を読むとわかります。

特に、Web標準の策定プロセスが今ほど洗練されていなかった時代に実装された機能については、多くの闇を生み出しているようです。例えば、window.onerrorというエラー時に呼び出される関数内では、エラー処理完了時に通常はfalseを返します。ただし、歴史的経緯から、Firefoxだけはtrueを返さなければいけないそうです。

このような問題に対処するには、本来の処理に加えて、どのブラウザで実行されているのかをチェックする「ブラウザテスト」を実施しなければいけません。 (なお現在では、window.onerrortry-catchによって代替され、ほとんど使われていません。)

特にブラウザ互換性についての話題で言及されやすいInternet ExplorerIE)については、本書でも「非互換性の多くは、IEに関連したものです」と、名指しで批判されています。

古いIEでは、Web標準として勧告されたメソッドを実装せず、同様の機能を持った別名のメソッドを使っていたりします。 例えば、IE8以前ではイベントハンドラを登録するaddEventListener()が実装されていなかったため、代わりにattatchEvent()というメソッドを使う必要があったそうです。

if (window.addEventListener)
    window.addEventListener("load", f, false);
else if (window.attachEvent) // IE8以前
    window.attachEvent("onload", f);

IEが天下を取っていた時代は、大半のWebページはIEで動けば問題なかったのでしょう。そんなIEに対抗するブラウザが登場し、健全な競争や議論の中でWebの標準化が進んだことは、非常に喜ばしいことだと思います。

また、Web標準の策定プロセスが整備されたことに加えて、Microsoft Edgeの登場、ブラウザ間の差異を埋めるPolyfillなどのライブラリの存在によって、ブラウザ間の差異を前ほど意識せずにJavaScriptを書くことができる環境になりつつあります。

かつてのjQueryがもたらした価値

サイ本では、第19章の約70ページ全てを、丸々jQueryの紹介に割いています。JavaScriptの1ライブラリとしては、破格の待遇です。

2012年当時、jQueryJavaScriptライブラリとしてデファクトスタンダードであったことがわかります。

今でこそ目の敵にされているjQueryですが、当時これほど流行った理由がサイ本を読んでいてわかりました。

前述のように、当時のフロントエンドの開発者はブラウザ間の差異から来る闇に苦しんでいました。生のJavaScriptではなくjQueryを使うことで、ブラウザ間の差異を吸収してくれ、どのブラウザでも同じように動作するJavaScriptを生成することができました。

また、JavaScriptやブラウザ自体の機能がまだ脆弱だった頃、jQueryは強力なAPIをどんどん追加していき、JavaScriptができることを広げていったようです。

jQueryAPIを覚えるだけで、ブラウザ互換性に配慮した動的なWebページを開発することができるとなれば、これほど使われるようになるのも必然でしょう。

ただし、現在では前述のようにブラウザ間の差異を前ほど意識せずにフロントエンド開発ができる環境が訪れつつあり、jQueryが果たした本質的な役割の意義が薄れつつあります。

また、jQueryのようなDOMへの要素挿入を中心としたアプローチではなく、宣言的なViewの管理によって要件を実現するVue.jsなどのJavaScriptフレームワークが、保守性などの観点から流行しています。一般にVue.jsなどが管理しているDOMを後からjQueryで書き換えるとアプリケーションがぶっ壊れるので、脱jQueryを進めるWebページやWebアプリケーションが増えている印象です。

もしも『JavaScript 第7版』が出版されたら、きっと『第19章 jQueryライブラリ』は無くなっているでしょう。

ブラウザにはワクワクする機能がたくさん追加されている!

サイ本の最終章である『22章 HTML5 API』では、以下のように当時では比較的新しかったAPIの仕様に関して言及されています。

  • 履歴管理
  • クロスオリジンメッセージング
  • Web Workers
  • Geolocation
  • IndexedDB

この本では「未来のAPI」のように語られているこれらのAPIですが、例えば「履歴管理」はSPAで戻るボタンを押せば当たり前のように機能しますし、Web Workersの1つであるService WorkersもついにiOS Safariで対応され、主要ブラウザ全てでPWAのキャッシュやプッシュ通知に使われ始めています。

ブラウザの仕様が目まぐるしく変わることで、そのキャッチアップが大変であったり、多くの負債が生まれたことは、前述の通りです。しかし、逆に新しい仕様が次々と登場することで、ブラウザで実現可能な範囲は毎年広がっています。例えば、「ブラウザ経由で位置情報を特定してその場所に応じたコンテンツを出す」みたいなことも、ブラウザの標準機能で実現できるようになっています。

また、この本に書かれた後に登場してきた新しい仕様によって、以下のような世界が当たり前になっていくかもしれません。

  • WebAssemblyで、C言語で書かれた世界中の資産がブラウザ上から使える
  • Payment Request APIで、ブラウザに登録しておいた支払方法や配送先を選ぶだけでブラウザ経由で決済できる
  • Web Publicationsで、HTMLで書かれた文書をそのまま電子書籍として閲覧、出版できる

JavaScriptを取り巻くエコシステムについて学び続けていると、そんなワクワクする話題がたくさん登場して、とても楽しい毎日を送れます。

この本について

ここまでサイ本を比較的ボジティブに解説してきましたが、正直に言って、JavaScriptを勉強したい多くの人には、この本はあまりおすすめではありません。『JavaScript 第6版』自体がかなり古くなっていて、最新のJavaScript事情を反映できてないからです。また、リファレンス的に利用するならまだしも、全章を読破するには、JavaScriptを記述する上では不要な内容が多い印象があります。

僕もJavaScriptを学び始めた当初は、サイ本より先に、『開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質』という本を読みました。

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質

こちらの本の方が、JavaScriptのハマりポイントである以下のような点について、たくさんの例を交えて簡潔に記述されています。

  • プリミティブ型とオブジェクト
  • this
  • スコープとクロージャ
  • プロトタイプ継承

JavaScript初心者が中級者に上がるための本としては、こちらの『開眼! JavaScript』の方をおすすめします。

また、リファレンス的に利用するにしても、MDN Web DocsJavaScriptの最新仕様やブラウザ互換性についてよくまとまっているので、そちらの方が使い勝手としては良いでしょう。

「サイ本がこれだけ分厚いなら、JavaScriptのより低レイヤな領域についても記載があるだろう」と思う人もいるかもしれないですが、特にメモリ管理の話とかも出てこないです。

なので、仮に『JavaScript 第6版』を勧めるとしたら、「ある時点でのJavaScriptの仕様を、その歴史も交えて体系的に知りたい」人に対してのみになるかと思います。もしそのような奇特な人がいたら、ぜひ挑戦してみてください。

最後に、改めてサイ本こと『JavaScript 第6版』の目次を掲載します。

第I部 コアJavaScript

  • 2章 字句構造

  • 3章 型、値、変数

    • 3.1 数値
    • 3.2 テキスト
    • 3.3 論理値
    • 3.4 nullとundefined
    • 3.5 グローバルオブジェクト
    • 3.6 ラッパーオブジェクト
    • 3.7 不変な基本型値と可変なオブジェクト参照
    • 3.8 型の変換
    • 3.9 変数の宣言
    • 3.10 変数のスコープ
  • 4章 式と演算子

    • 4.1 単項式
    • 4.2 オブジェクトと配列の初期化子
    • 4.3 関数定義式
    • 4.4 プロパティアクセス式
    • 4.5 呼び出し式
    • 4.6 オブジェクト生成式
    • 4.7 演算子の概要
    • 4.8 算術演算子
    • 4.9 関係演算子
    • 4.10 論理演算子
    • 4.11 代入演算子
    • 4.12 評価式
    • 4.13 そのほかの演算子
  • 5章 文

    • 5.1 式文
    • 5.2 複合文と空文
    • 5.3 宣言文
    • 5.4 条件文
    • 5.5 ループ文
    • 5.6 ジャンプ文
    • 5.7 そのほかの文
    • 5.8 JavaScript文のまとめ
  • 6章 オブジェクト

    • 6.1 オブジェクトの生成
    • 6.2 プロパティの読み出しと書き込み
    • 6.3 プロパティの削除
    • 6.4 プロパティのテスト
    • 6.5 オブジェクトプロパティの調査
    • 6.6 プロパティのゲッターメソッドとセッターメソッド
    • 6.7 プロパティ属性
    • 6.8 オブジェクト属性
    • 6.9 オブジェクトのシリアライズ
    • 6.10 オブジェクトのメソッド
  • 7章 配列

    • 7.1 配列の生成
    • 7.2 配列の要素の読み書き
    • 7.3 疎な配列
    • 7.4 配列の長さ
    • 7.5 配列の要素の追加と削除
    • 7.6 配列の要素の巡回
    • 7.7 多次元配列
    • 7.8 配列のメソッド
    • 7.9 ECMAScript 5の配列メソッド
    • 7.10 配列の種類
    • 7.11 配列のようなオブジェクト
    • 7.12 配列としての文字列
  • 8章 関数

  • 9章 クラスとモジュール

    • 9.1 クラスとプロトタイプ
    • 9.2 クラスとコンストラクタ
    • 9.3 JavaScriptでのJavaスタイルのクラス
    • 9.4 クラスの拡張
    • 9.5 クラスと型
    • 9.6 JavaScriptでのオブジェクト指向的な技術
    • 9.7 サブクラス
    • 9.8 ECMAScript 5のクラス
    • 9.9 モジュール
  • 10章 正規表現パターンマッチング

    • 10.1 正規表現の定義
    • 10.2 パターンマッチング用の文字列メソッド
    • 10.3 RegExpオブジェクト
  • 11章 JavaScriptのサブセットと拡張

    • 11.1 JavaScriptのサブセット
    • 11.2 定数とスコープ付きの変数
    • 11.3 分割代入
    • 11.4 反復機構
    • 11.5 簡易表記関数
    • 11.6 複数のcatch節
    • 11.7 E4XECMAScript for XML
  • 12章 サーバサイドJavaScript

第II部 クライアントサイドJavaScript

  • 13章 Webブラウザに組み込まれたJavaScript

    • 13.1 クライアントサイドJavaScript
    • 13.2 HTMLドキュメントへのJavaScriptコードの埋め込み
    • 13.3 JavaScriptプログラムの実行方法
    • 13.4 互換性と相互運用性
    • 13.5 アクセサビリティ
    • 13.6 セキュリティ
    • 13.7 クライアントサイドフレームワーク
  • 14章 Windowオブジェクト

    • 14.1 タイマー
    • 14.2 ブラウザのLocationオブジェクトと移動
    • 14.3 閲覧の履歴
    • 14.4 ブラウザと画面情報
    • 14.5 ダイアログボックス
    • 14.6 エラー処理
    • 14.7 Windowプロパティとしてのドキュメント要素
    • 14.8 複数のウィンドウとフレーム
  • 15章 ドキュメントの制御

    • 15.1 DOMの概要
    • 15.2 ドキュメント要素の選択
    • 15.3 ドキュメント構造と探索
    • 15.4 属性
    • 15.5 要素のコンテンツ
    • 15.6 ノードの作成、挿入、削除
    • 15.7 例:目次の作成
    • 15.8 ドキュメントと要素位置とスクロール
    • 15.9 HTMLフォーム
    • 15.10 ドキュメントのそのほかの機能
  • 16章 CSSの制御

    • 16.1 CSSの概要
    • 16.2 重要なCSSプロパティ
    • 16.3 インラインスタイルの制御
    • 16.4 算出スタイルの取得
    • 16.5 CSSクラスの制御
    • 16.6 スタイルシートの制御
  • 17章 イベント処理

    • 17.1 イベントタイプ
    • 17.2 イベントハンドラの登録
    • 17.3 イベントハンドラ呼び出し
    • 17.4 ドキュメントのloadイベント
    • 17.5 マウスイベント
    • 17.6 マウスホイールイベント
    • 17.7 ドラッグ&ドロップイベント
    • 17.8 テキストイベント
    • 17.9 キーボードイベント
  • 18章 HTTPの制御

    • 18.1 XMLHttpRequestの利用方法
    • 18.2 <script>によるHTTP制御:JSONP
    • 18.3 Server-Sent Eventsを使ったComet
  • 19章 jQueryライブラリ

    • 19.1 jQueryの基本
    • 19.2 jQueryのゲッターとセッター
    • 19.3 ドキュメント構造の変更
    • 19.4 jQueryでのイベント処理
    • 19.5 アニメーション効果
    • 19.6 jQueryによるAjax
    • 19.7 ユーティリティ関数
    • 19.8 jQueryセレクタと選択メソッド
    • 19.9 プラグインによるjQueryの拡張
    • 19.10 jQuery UIライブラリ
  • 20章 クライアントサイドストレージ

    • 20.1 localStorageとsessionStorage
    • 20.2 クッキー
    • 20.3 IEのuserData永続化機構
    • 20.4 アプリケーションストレージとオフラインWebアプリケーション
  • 21章 メディアとグラフィックの制御

  • 22章 HTML5 API

    • 22.1 Geolocation
    • 22.2 履歴管理
    • 22.3 クロスオリジンメッセージング
    • 22.4 Web Workers
    • 22.5 型付き配列とArrayBuffer
    • 22.6 Blob
    • 22.7 Filesystem API
    • 22.8 クライアントサイドデータベース
    • 22.9 WebSocket
  • 索引