JavaScript連載第16回

クロスブラウザJavaScript入門第16回が公開されています。
今回はthisのお話です。この辺はクロージャとかも絡んでくるので、(記事中にも書きましたが)JavaScript初級から中級への分かれ目になってくると思います*1
まあ、そのせいでソースを理解してもらいにくくなりそうなので、微妙に使いにくさがあるように思えます。実際、クロージャやプロトタイプを使うほど一見綺麗に書けているように見えて自己満足度はあがるけど、それをわかりやすいと思うのは自分だけということになりかねません(もちろん、必ずそうなるってわけではないですが)。
プロトタイプのほうに凝りだすとライブラリ化、つまりなるべく汎用的に動くようなコードを書くようになり、必然的にソースが肥大化していくことがままあります。それはそれで悪いことではないですが、個人的には最小限のコードでコンパクトに実装するほうが好みです(もちろん場合によりけりですが)。

*1:まあ、「thisはargumentsと同じなんだよ」の一言で大体あってる気もするこの頃ですが

Mashup Camp - Chrome Extensions Day開催

Mashup Awards 6関連で#MA6 Mashup Camp - Chrome Extensions / Web Apps Day (未経験者歓迎 JavaScript できれば OK) : ATNDが開催されます。Mashup Awards 6に向けて、参加者でグループを作ってコードを書こうというイベント(いわゆるハッカソン)です。
10月5日の夜にアイディア出し・顔合わせMTG、10月9日に一日コーディングというスケジュールです。
私もアドバイザーとして参加します。なお、同じアドバイザーとして、Googleの北村英志さんも参加します。GDD2010の基調講演やChrome Web Storeのセッションなどで活躍していたあの人です。
もう数日後なので急過ぎるかもしれませんが、Mashup Awardsに興味のある方、Chrome拡張に興味のある方は是非ご参加頂ければと思います。

JavaScript連載第15回

Bootcamp2010GDD2010でこっちに書くのが遅れましたが、クロスブラウザJavaScript入門第15回が公開されています。
前回に引き続きprototypeのお話。このシリーズではあえてクラスとかチェーンといった言葉も避けています。他ではあまり見かけない説明の仕方で、(主観的に)こう説明されていればすんなり理解できるという内容を目指していますが、まだまだ力不足な感は否めません…。
ただ、今回の数学の証明っぽいところは結構お気に入りです。

あれ、全然クロスブラウザしてないですか?気のせいですよ、きっと。

valueOfとtoStringとToPrimitive

valueOfとtoStringメソッドの水深43cmぐらいの深さの話 - 三等兵のもう少し深いお話。コメント欄に書こうかとも思ったけど、最近ブログ書いてない気がしたのでちゃんと記事にしてみる。

まずは問題です。次のコードを実行したときにtrueかfalseのどちらがalertされるかそれぞれ当ててみてください。

var date = new Date();
var date_string = date.toString();
var date_value = date.valueOf();
alert(date == date_string);
alert(date == date_value);
  1. true, true
  2. false, false
  3. true, false
  4. false, true

(難しい問題ではないと思いますが、)この問題の答えは最後に。

続いて、もっとシンプルな問題です。

var d = new Date('2000/01/1');
alert(d+1);

選択肢は次の3つです。

  1. Sat Jan 01 2000 00:00:00 GMT+09001
  2. 946652400001
  3. [object Date]1

1)はDateをtoStringした値、2)はvalueOfした値、3)はObject.prototype.toString.call(d)の値です。


この問題の答えは1です。これはよくハマるところなので、そういうものだと思っている方も多いと思います。
最初の問題もそうですが、DateのtoStringが文字列を、valueOfがシリアル値を返すことを知っていれば、正解できると思います。

余談ですが、DateをtoStringしたときの結果はブラウザによって微妙に結果が異なります。

  • Firefox/Opera
    • Sat Jan 01 2000 00:00:00 GMT+0900
  • Google Chrome
    • Sat Jan 01 2000 00:00:00 GMT+0900 (Japan Standard Time)
  • Safari(Mac)
    • Sat Jan 01 2000 00:00:00 GMT+0900 (JST)
  • Safari(Windows)
    • Sat Jan 01 2000 00:00:00 GMT+0900 (???? (?W?Ž?))
  • IE
    • Sat Jan 1 00:00:00 UTC+0900 2000

IEさんはともかく、Windows版Safari*1

さて、なぜ1になるのかを詳しくみてみましょう。

まず、変数dはDateのインスタンスであり、オブジェクトです。そのオブジェクトに加法演算子(+)で1を渡しています。
加法演算子の仕様はECMA-262の11.6.1で定められています*2
その前半部分は次のようになっています。ここではAdditiveExpressionは左項、MultiplicativeExpressionは右項と読み替えてしまえばわかりやすいと思います*3

  1. AdditiveExpression を評価。
  2. GetValue(Result(1)) を呼出す。
  3. MultiplicativeExpression を評価。
  4. GetValue(Result(3)) を呼出す。
  5. ToPrimitive(Result(2)) を呼出す。
  6. ToPrimitive(Result(4)) を呼出す。

つまり、d + 1のそれぞれ d と 1 をToPrimitiveという内部処理に渡しています。
ToPrimitiveはつまりは型変換であり、ECMA-262の9.1で定義されています。
このToPrimitiveですが、オブジェクト以外の型についてはなにもしません。つまり1は1のままです。1はもともとプリミティブな値なので当然ですね。
さて、もう一方のdはDateオブジェクトです。なのでプリミティブ化処理が行われます。その内容は次のように定義されています。

Object のデフォルトの値を返す。オブジェクトのデフォルトの値は、オブジェクトの内部メソッド [[DefaultValue]] に選択的ヒント PreferredType を渡して取得される。[[DefalutValue]] メソッドの挙動は、全ての ECMAScript オブジェクトの仕様によって定義される。(セクション 8.6.2.6)

今度は[[DefaultValue]]というのが出てきました。上記に書かれている通り、[[DefaultValue]]はECMA-262の8.6.2.6で定義されています。
これによると、[[DefaultValue]]がStringをヒントに呼び出されるとtoStringが、Numberをヒントに呼び出されるとvalueOfを呼びだすと定義されています。toStringとvalueOfを呼び分けているのはここです。ここ大事ですね。
さて、ヒントとはなんでしょうか。と、これはすでにちょこちょこと出てきていて、加法演算子のNOTEには、次のような記述があります。

NOTEステップ 5 と 6 における ToPrimitive 呼出しではヒントを提供しない。全ネイティブ ECMAScript オブジェクトは Date オブジェクトを除き、ヒントの欠如をヒント Number が与えられたように扱う; Date オブジェクトは、ヒントの欠如をヒント String が与えられたように扱う。

[[DefaultValue]]のNOTEにも同様の内容が記述されています。Date オブジェクトだけはStringをヒント、つまりtoStringが呼ばれると定義されていました。

さて、こんな面倒なことになっている原因はなんでしょうか?それは+が、文字列の連結としての加算演算子と数値の加算としての加算演算子という2つの意味を持ってしまっているからです。-、*、/などは数値演算であることが明確なので、そもそもToPrimitiveではなくToNumberが呼ばれ、ToNumberは(オブジェクトに対して)ToPrimitiveをNumberをヒントに呼び出すことになります。

また、加算演算子以外にも、==と!=(抽象的等価比較)についても場合によってヒントなしのToPrimitiveが呼ばれることがあります。具体的には、オブジェクトとプリミティブ値が比較された場合です。

最初の問題に戻ってみましょう。

var date = new Date('2000/01/1');

var date_string = date.toString();
// Sat Jan 01 2000 00:00:00 GMT+0900
alert(date == date_string);

dateはオブジェクトで、date_stringは文字列なので、11.9.3 抽象的等価比較アルゴリズムのステップ21からToPrimitive(date)が呼ばれ、その中でtoStringが呼ばれます。結果、dateとdate_stringは一致します。

var date_value = date.valueOf();
// 946652400001
alert(date == date_value);

dateはオブジェクトで、date_valueは数値なので、同じく11.9.3 抽象的等価比較アルゴリズムのステップ21からToPrimitive(date)が呼ばれ、その中でtoStringが呼ばれます。dateは文字列になり、date_valueは数値なのでこちらは一致しません。
というわけで、最初の問題の答えは3でした。

おまけで、以前話題になったwtfjsから、こちらを読み解いてみると面白いと思います。

[] == ![] // true

http://wtfjs.com/2010/02/15/careful

*1:windows版リリース当初からバグッたまま

*2:ホントは5th editionも参照するべきなんだけど、ざっと見た感じ特に変更はなさそうなので割愛

*3:左項、右項って日本語はなさそうですが、伝わると思います

JavaScript連載第14回とデベロッパーツール特集

デベロッパーツール特集最終回クロスブラウザJavaScriptのほうは第14回が公開されています。
デベロッパーツールの最終回は細かいネタを集めた感じに。個人的な一押しはChrome6から実装された about:about です。about:〜って2年前から何度かネタにされていると思いますが、そこそこ有用で使えるヤツはこのabout:aboutでカバーされているはずです。ただ、一部ミドルクリックから開かないと機能しなかったり、ブランクページが表示されるものがあったりしますが…。もちろん、Chrome7ならabout:labsも追加されていますよ。

クロスブラウザJavaScriptは基礎編に戻ってprototypeについて。あんまりクロスブラウザしてないけど、まあ折角なのでこのままthisとかcallとかについてかなり詳しく解説していこうと思います。
うーん、書こうと思えばいくらでも書けそうなほどネタはあるはずなんだけど、書くペースがなかなか上がらない、むしろ落ちている…。頑張らねば。

HTML5ガイドブック

Google API Expertが解説するHTML5ガイドブック

Google API Expertが解説するHTML5ガイドブック


インプレスさんより、Google API Expertが解説する HTML5ガイドブックという本が2010/09/16に発売されます。
@futomiさん(Canvas、Drag&drop、FileAPI)、@Shumpeiさん(ApplicationCache、WebSocket、WebWorker)、@openspcさん(Video&Audio、Geolocation)に私(SVGと付録でECMAScript5とCSS3 Transitions)の4人での共著です。
内容はHTML5、というよりHTML5の関連APIについてです。HTML5の仕様自体についてはそれほど触れていません(特に私は…)。
というのも、HTML5の仕様自体というのは、これまでDOM Level0と呼ばれていたような各ブラウザで大体同じような動きをするけど仕様にはなっていなかったところや、間違ったHTMLについてブラウザはどう解釈するべきかとか、ブラウザを実装する側向けに定義された部分が少なからずあります。もちろんそれ以外にも色々ありますが、基本的に細かいトピックスの集合です(大きいトピックスは分離される傾向がありますし)。
多くのウェブ開発者にとって興味があると思われる新しいAPI(CanvasとかWebWorkerとかWebSocketとか色々)についてはHTML5の関連APIと呼ばれていて、HTML5自体の仕様ではないものが多いです。で、今回のHTML5ガイドブックはそういった新しいAPIを中心にした解説本です。多くの方にとって興味があるのはそういった新しいAPIだと思いますので、(安心して?)手にとって頂ければと思います。
ただ、新しいAPIと書きましたが私が担当したのはSVGだったりします…。SVG自体はどこも新しくないんですよね。ただ、HTML5(の仕様)でHTML中に直接SVGを書けるようになる(IE9やFirefox4にChrome7では既に実現済み)ので、今後はHTMLとの連携がポイントになってくるってところをネタに書きました。で、ご察しの通り特集:スタートアップ SVG|gihyo.jp … 技術評論社とテーマ的にも時期的にも被っています…。
ただ、SVG以外にECMA-262 5th Edition(ECMAScript5)についても付録として書きました。ECMAScript5はまだ解説記事が少ない(と思う)ので、結構しっかり書いたつもりです。特にECMAScript5では読み取り専用属性などを定義できるようになったりと、大規模開発を意識した改訂が加えられています。HTML5でウェブアプリケーションが高度になっていくのに関連して、ECMAScript5もそれに適した言語へと進化しようとしています。そのあたりを是非チェックして頂ければと!
では、HTML5ガイドブックをよろしくお願いいたします。

デベロッパーツール特集第3回

Google Chrome版Firebug:デベロッパーツール取扱説明書の第3回はウェブサイトの最適化です。
Timelineパネル、Auditsパネルの使い方を解説しました。正直なところ、こういう最適化が必要なケースってあんまり少ないんじゃないかなーと思わないこともないのですが、知らずにやるのと知ってて無視するのとでは何かあったときに致命的な違いにもなり得るので、どういうものか見て頂ければと。
記事では「こういったツールの結果は参考にしつつも過信しないようにしましょう。」と締めているのですが、「これらのツールを使ってサイトをガンガン高速化しちゃいましょう!」みたいに締める方が「よくある」んだと思います。自分がそういうやり方が好きじゃないので意図的にそうしてますが、デベロッパーツールに関してはもっと受ける(釣れる)ようにしてとにかく広めることを目的にしても良いんじゃないかと思ったりもしています。(タイトルを取扱説明書なんて控えめにしないで、「まだFirebugをお使いですか?」みたいな。やらないけどね。)