出版社より献本御礼。

待ってましたこういうの。

EcmaScript 5のサポートが一通り完了して、これからHTML5のAPIが充実していくという今は、JavaScriptを学ぶ最高の旬。だけどWebの情報は断片的で、折角の新APIを使おうにもどこから手をつけていいのかわからなかった。これで勝つる。

本書「JavaScript逆引きハンドブック」は、「Ruby逆引きハンドブック」の出版社によるJavaScriptのシソーラス。「辞書」や「参考書」なら巷にあふれかえっているJavaScriptであるが、これがなかなかなかった。ましてやES5にHTML5といった最新の機能をカヴァーしているものとなると、なおのこと。

目次 - 書籍詳細|株式会社 C&R研究所より
■CHAPTER 01 JavaScriptの基礎知識と基本文法
■CHAPTER 02 オブジェクト
■CHAPTER 03 配列
■CHAPTER 04 数値・数学
■CHAPTER 05 文字列・正規表現
■CHAPTER 06 日付・時刻
■CHAPTER 07 ブラウザオブジェクト
■CHAPTER 08 DOM
■CHAPTER 09 イベント
■CHAPTER 10 Canvas/Canvas 3D/SVG
■CHAPTER 11 Audio/Video/HTML Media
■CHAPTER 12 File API
■CHAPTER 13 HTML5のその他のAPI
■CHAPTER 14 スタイルシート

1000ページ弱。これに購入者特典のサンプルコードがつく(ダウンロード方法はP.5を参照)。Zipで86.6MB。かなりの分量であるが気圧される心配はない。なにしろ本書は逆引きハンドブック。必要なところだけつまみ食いすればよい。

で、最新のブラウザーを使うと何が出来るか。

例えば、こんなことができる。

Demo:

Info:
Content:
RGB:

適当な画像ファイルを選択してして欲しい。SafariやChromeであれば、"Choose File…"のところにファイルをドロップしてもよい。ここでは画像を三原色分解しているだけだが、重要なのはこれはブラウザーのみで、サーバーは一切使っていないこと。つまり、ブラウザーだけでファイルを加工できてしまうのだ。ちなみにこれは本書のサンプルコードからの転載ではなく、本書を見ながら私が書き下ろしたもの。

こういう機能は実は前からあったし、意外なところで意外なサイトが使っていたりもするのだけど、じゃあ自分で書こうと思ったら途方にくれるか勉強会などで「達人」に直接話を聞くほかなかった。検索しようにもキーワードすらわからないし、運よく引っかかっても玉石混淆、というか石ばっかりというのが現状。たとえば上記のFile APIは一応…

…とかにもあるのだが、お世辞にもきれいなコードとは言えない("HTML5 Rocks"っていいつつソース中にタグを直書きするとかどんだけ)。かといってjQueryとか使うときれいに楽にコードが書けるのはいいけれど、かゆいところに手が届かなかったりする。

本書がえらいのは、そういったことをVanilla JSで書き下していること。サイ本すらjQueryが顔を出すのに、本書にはまるで登場しない(少なくとも索引にはない)。

とはいえJavaScriptという言語はとにかく、JavaScriptというプログラミング環境の進化は早い。例えば上のコード、本書によればSafariとIEでは動かないことになっているのだが、Safari 6 と IE 10 ではあっさり動いてしまった。

それでは本書も類書同様、賞味期限が短いのかという懸念はあるが、前述のとおりJavaScriptは今が旬。Chromeぐらいしかサポートしてなかった機能が他でもどんどん使えるようになってきている。IEでさえその例外ではない。その意味でむしろ本書は購入以降も熟していくとさえ言える。

それにしても、blinkタグとかIE6とかを体験しないでWebプログラミングを学べる若者が羨ましい。本書のコードサンプルもaddEventListener()を直に使っている。昔はそれさえ許されなかった(今もですか?IE6を推奨しているサイトのWebマスター各位)。本書片手に(ちゃんと片手でも持てるように薄めで丈夫な紙使ってます)いろいろ遊んでほしい。大丈夫、今なら(昔ほどは)けがしないから。

Dan the JavaScripter

Demo Source:

HTML


JavaScript

(function(global){

if (!global.FileReader) return; /* throw new Error('FileReader not supported'); */

var $ = function(id){ return document.getElementById(id) };
var clearImg = function(){
    $('theImage').src = 
        $('theImageR').src = $('theImageG').src = $('theImageB').src
        = 'data:image/gif;base64,'
        + 'R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
};
var readImg = function (file, img, onload) {
    var reader = new FileReader();
    reader.onload = function (ev) {
        img.src = ev.target.result;
    };
    reader.readAsDataURL(file);
    if (onload) img.onload = onload;
};
var rgb = function(){
    var img = this;
    var cv  = document.createElement("canvas"),
    ctx = cv.getContext("2d"),
    w   = cv.width  = cv.style.width  = img.width,
    h   = cv.height = cv.style.height = img.height;
    ['R', 'G', 'B'].forEach(function(color, idx){
        ctx.drawImage(img, 0, 0);
        var imgdata = ctx.getImageData(0, 0, w, h),
            data    = imgdata.data;
        for (var i = 0; i < data.length; i += 4) {
            if (idx !== 0) data[i + 0] = 0;
            if (idx !== 1) data[i + 1] = 0;
            if (idx !== 2) data[i + 2] = 0;
        }
        ctx.putImageData(imgdata, 0, 0);
        $('theImage' + color).src = cv.toDataURL('img/png');
    });
};
var readit = function () {
    var file = $('theFile').files[0],
        info = {
            name: file.name,
            lastModifiedDate: file.lastModifiedDate,
            size: file.size,
            type: file.type
        };
    $('fileInfo').textContent = JSON.stringify(info, null, '  ');
    if (file.type.indexOf('image') === 0) {
        readImg(file, $('theImage'), rgb);
    } else {
        clearImg();
    }
};

$('theFile').addEventListener('change', readit, false);
$('readIt').addEventListener('click', readit, false);
clearImg();

})(this);