Posted at

JavaScriptは比較演算子"も"推移関係が成り立っていない件

More than 1 year has passed since last update.

※この投稿は 2010/07/21 に こちら に投稿した記事の転載です。

タイトルの通りのおはなしです.


推移関係 is 何?

推移関係 (transitive relation) っていうのは,「風が吹けばほこりがたつ」「ほこりがたてば(略)桶屋が儲かる」だから「風が吹けば桶屋が儲かる」っていう三段論法みたいなやつですね.

一般的には関係 R が,どんな組み合わせの a, b, c についても下のように言えるとき,R は推移的であるといいます:

a R b で b R c なら a R c

数値の大小比較が推移的だというのは直感的にわかるはず.

a < b で b < c なら a < c

ですもんね.

で,上で使った < 演算子が,JavaScriptでは推移的ではないよ,というのが本題.


証明

推移的でないことを示すのは簡単で,ひとつでもいいから上の法則が成り立っていない a, b, c の組み合わせを見つけてやればいいだけ.

ここで以下の組み合わせを考える:

a = 1;

b = "2";
c = "three";

これをブラウザのコンソールで実行してみると、結果は以下のとおり:

Screenshot_1.png

見事に反例を示すことが出来ました.


なぜこんなことに…?

なんでこんな結果になるのかというと,JavaScriptの < は,両辺が文字列だった場合は文字列の辞書順で大小比較をするんですね.

どちらか片方でも文字列でなかった場合は,数値に変換して比較するわけです.

そのため,値の型が揃っていない場合にはこんな珍妙なことが起きるというわけですね.

そういえばタイトルに「"も"」と書きましたが,JavaScriptでは同様に == 演算子も推移関係を満たしていないのですよ.

これは ECMAScript 3rd Edition の仕様書で言及されているくらい有名な(?)事実:


NOTE 3 The equality operator is not always transitive. For example, there might be two distinct String objects, each representing the same String value; each String object would be considered equal to the String value by the == operator, but the two String objects would not be equal to each other.


文章で読むとなんだかわかりにくいですが,こういう意味ですね↓

a = new String("hoge");

b = "hoge";
c = new String("hoge");

として,皆さんも実行してみてください:

Screenshot_3.png

ほらね!

だったら < についてもNOTEしておけよ!とか思ったのは,別の話(ぉ