BK通信 - JavaScript のバッドノウハウ

最終更新日: 2008-07-01

WEB+DB PRESS Vol. 44 に向けて書いた記事の元の原稿です。


今月号から「BK通信」と題して、連載することになった高林と申します。先月号まで連載していた「プログラミングの光景」ではデバッグ、コードレビューといった大きなテーマを取り上げましたが、今回の連載では日常的に遭遇するチマチマした「バッドノウハウ」について書いていきたいと思います。

バッドノウハウとは?

バッドノウハウとは、私が2003年に作った造語です。元の定義は以下のようなものです*1

計算機を使っていると、何でこんなことを覚えないといけないのだろうか、とストレスを感じつつも、それを覚えないとソフトウェアを使いこなすことができないためにしぶしぶ覚えなければならない、といった類いのノウハウは多い。そうした雑多なノウハウのことを、本来は知りたくもないノウハウという意味で、私はバッドノウハウと呼んでいる。

一方、「はてなキーワード」にある定義は簡潔ですっきりしています。

ソフトウェアなどを使いこなすために、ストレスを感じながらもしぶしぶ覚えなければならないようなノウハウ。

本連載では私が遭遇して「こ、これはバッド...」と絶句したバッドノウハウ (以下、 BK) を紹介していきたいと思います。「うわ、これバッドだなあ」とか「オレもこれにはまった!」などと共感して楽しんでもらえれば何よりです。

JavaScript の sort 関数

JavaScript の配列には sort 関数が定義されています。配列をソートしたければこの関数を呼べばOK!と思いきや、予期せぬ挙動に悩まされました。何でだろうと思って調べると、数値の配列をソートしても、文字列の順序でソートされているのが原因でした。

% js  # SpiderMonkey のインタプリタを実行
js>  [3, 1, 10, 2].sort()
1,10,2,3

[3, 1, 10, 2] をソートしたら当然 [1, 2, 3, 10] になるはず、と思いきや、意外な挙動です。ECMAスクリプトの仕様書 *2を読むと、 sort() 関数に比較関数が渡されていない場合は、各要素は暗黙的に文字列に変換されると書かれています。

というわけで、比較関数を渡してやれば解決します。

js>  [3, 1, 10, 2].sort(function(a, b) { return a - b; })
1,2,3,10

知人に聞いてみると、JavaScript プログラマにとっては常識とのことでした。でも、これ、はじめて遭遇したときは誰でも「バッド...」とのけぞるんじゃないでしょうか。

ソートされてねーし
ソートされてねーし

JavaScript の配列末尾のカンマ

これもまた JavaScript プログラマには常識という話ですが、あるとき、配列を初期化するときの末尾のカンマの解釈が IE と他のブラウザで異なるという問題ではまりました。

var a = [1,2,3,]
alert(a.length);

上のスクリプトを実行すると IE (IE 7 で確認) では 4 を、その他のブラウザでは 3 を返します。JavaScript では配列の要素を省略して初期化することを許しており a = [1,,3] のような書き方が可能です (この場合の a.length は 3 で a[1] は空)。そう考えると一見、IEの方が正しそうですが、ECMAスクリプトの仕様書をよく読むと、最後のカンマは解釈が異なり、結局、IE の方が間違っているようです。

配列を初期化するコードを自動生成する場合、最後に余分なカンマをつけて出力する方が簡単なのですが、 IE の存在を考えると、律儀にカンマを取り除いてやる必要があります。バッドですね。

カンマ取り除きたくねーし
カンマ取り除きたくねーし

月のオリジン

JavaScript の Date は日付と時間の処理するのに使える便利なオブジェクトです。が、最初に使ったときは月がひとつずれるという問題にはまりました。

js> (new Date).toString()
Sun Mar 02 2008 21:31:43 GMT+0900 (JST)
js> (new Date).getMonth()
2

このように、3月のときは getMonth() は2を返します。つまり、 Date オブジェクトの月は 0 から始まっています。なんでこんなバッドな仕様なんだ、他の言語はどうなっているんだ、と思って以前に調べたところ、次のような結果になりました。

言語 (ライブラリ)       月のオリジン
=====================================
C (localtime)           0
Java (Calendar)         0
Perl (localtime)        0
JavaScript (Date)       0
Ruby (Time)             1
Ruby (Date)             1
Perl (DateTime)         1
Perl (Time::Piece)      1
Python (time)           1
Python (datetime)       1
PHP (getdate)           1
Scheme (srfi 19)        1
.NET (DateTime)         1

月を数字で表記する日本人にとっては 1から始まるの方が自然ですが、Jan, Feb, Mar などと主に名前で表記する英語圏の人にとっては 0 から始まってもあまり気にならないのかもしれません。むしろ、配列の添え字に使いやすいので 0 の方が好都合な面もありそうです。

いずれにしても、使う言語やライブラリによって月のはじまりが 0 なのか 1 なのか覚えるか調べないといけないのは、まさにBKといえます。

どっちかにして欲しーし
どっちかにして欲しーし

まとめ

今回は JavaScript の BK を3つ紹介しました。3つとも自分がはまった落とし穴ですが、選ぶとすればsort 関数の挙動が一番、バッド度が高い (はまりやすい) んじゃないかと思います。バッドバッド、といいつつも、実はなんだかんだで楽しんでいたりするのですが。


*1<http://0xcc.net/misc/bad-knowhow.html>
*2<http://www.mozilla.org/js/language/E262-3.pdf>