nyuhuhuu cc |
パーフェクトJavaScript (PERFECT SERIES 4)
プログラミング経験がない人は絶対に読むべきではないですが、他の言語でプログラミングの経験がある人がJavascriptを新たに勉強するには非常にオススメできるかなり良いテキストです。そう感じました。
同じ専攻の同期4人で勉強を進めていて、とりあえず初めから読んでいこうということになり、先週は1-2章を読み、今週は3章「Javascriptの型」を読み進めました。
ちなみに実行環境はFirefoxのWebコンソールやChromeのJSコンソールを使って対話的に行っています。
FirefoxはSpiderMonkey, Chromeはv8と処理系が異なるため、微妙に挙動が違うこともありますが、本ではSpiderMonkey準拠なので、Firefoxで試す方が良さそうです。
FirefoxのWebコンソール |
1. 文字列型と文字列クラスの比較
Javascriptには同値比較演算子が2つあり、==と===で挙動が異なる。var s1 = "abc"; // これは文字列値 var s2 = new String("abc"); // これは文字列クラスのインスタンス s1 == s2; // => true s1 === s2; // => falseこれは、==が暗黙の型変換をしてから比較するのに対し、===が型変換をせずに両辺の比較を行うところに原因がある。===をstrict equalという。
2. 文字列値の暗黙の型変換
var s = "abc"; s.length; // => 3 "abc".length; // => 3
文字列値sは値、文字列リテラル"abc"はリテラルでありオブジェクトではないのだが、暗黙の型変換により形式上プロパティアクセスをしているように見える。
これと同様の現象は数値クラスでも起こり、文字列クラスや数値クラスをnewする必要性はなくなる。さらばクラスベースオブジェクト指向!
3. オブジェクト型のインスタンスは参照型
こういう現象も起こる。var s1 = new String("abc"); var s2 = new String("abc"); s1 == s2; // => false s1 === s2; // => false s1+'' == s2+''; // => true s1+'' === s2+''; // => true文字列の内容は同じでも参照先のオブジェクトが異なるためfalseになる。一方、+''してやると暗黙の型変換により文字列値どうしの比較となるためtrueになる。
4. 文字列値から数値の型変換
数値クラスの関数呼び出しにより数値を得ることができる。var n1 = Number(1); // => 1 typeof n1; // => "number" var n2 = Number("1"); // => 1 typeof n2; // => "number" n1 + n2; // => 2 Number("1x"); // => NaN parseInt("1x"); // => 1 parseInt("x"); // => NaN parseInt("0xff"); // => 255 parseInt("ff", 16) // => 255 parseInt("ff", 10) // => NaN parseInt("0xff", 10); // => 0 parseInt("0.1"); // => 0 parseFloat("0.1"); // => 0.1
5. NaNの挙動
コードは書かないけど、NaNが現れたらどんな演算をしてもNaNになり、同値判定、比較演算も常にfalseが返される。値がNaNであることの判定をするにはグローバル関数のisNaNを使う。こういった挙動の理由はNaNがNot a Numberの略語であり、「数値ではない」と考えれば何かと足し合わせたり、比較しようとしても結果を定義できないことを考えると理解しやすい。
6. Booleanへの型変換の挙動
これはよく考えると当たり前のものもあるが、驚かされる。Booleanへの型変換はBoolean関数呼び出しで明示的に行え、暗黙的にはifやwhile文の条件式の中で暗黙の型変換が行われる。// Boolean値はそのまま var t1 = Boolean(true); // => true var f1 = Boolean(false); // => false // 数値は0とNaNがfalseになり、それ以外はtrue var t2 = Boolean(1); // => true var t3 = Boolean(-1); // => true var f2 = Boolean(0); // => false var f3 = Boolean(NaN); // => false // 文字列値は空文字列値""以外はtrueになる var t4 = Boolean("abc"); // => true var t5 = Boolean("false"); // => true var f4 = Boolean(""); // => false // null値、undefined値はfalseになる var f5 = Boolean(null); // => false var f6 = Boolean(undefined); // => false中でもBoolean("false")がtrueになるのは注意したい。
7. nullとundefinedの違い
nullは何も参照していない状態を表す値で、null型にはnull値の1つしかない。null値はリテラル値。undefinedは何も定義されていない状態を表す変数で、undefined型にはnull同様undefined値の1つしかない。だがこれはリテラル値ではなくあくまで変数(読み込み専用)。
8. Javascriptのイディオム
3で書いたような表現はクライアントへの転送量を削減するためのイディオムだったりする。他のスクリプト言語でも普通に使われるようなものもあったが、面白いものがいくつかあったのでまとめてみる。// 数値から文字列値 var n = 1; n+''; // 数値1から文字列値"1"への型変換 typeof(n+''); // => "string" // 文字列値から数値 var s = "1"; +s; // 文字列値"1"から数値1への型変換 typeof(+s); // => "number" // Boolean型へ !!1; // => true !!0; // => false !!''; // => false !!null; // => false // オブジェクト型からBoolean型 // この場合は何を受け取っても必ずtrueとなるので注意 Boolean(new Boolean(false)); // => true Boolean(new Number(0)); // => true Boolean(new String('')); // => true!!1と!!0はすごいと思った。二重否定かぁ。
まとめ
今までクライアントサイドもそれなりに書いてきましたが、ググってコピペしたり、jQueryをこねくり回したりと、Javascriptと真剣に向き合ってきませんでした。このままではいかんと取り組んでみた結果、Javascriptに限らないものもありますが、面白い言語だなぁと感じました。やってみてよかったです。Boolean("false")やBoolean(new Boolean(false))がtrueになったりと直感に反する部分もありますが、でもよく見てみると論理的で、ほかの動的型付けをする言語とはまた違うなぁという印象です。これからどんどん学習を進めていきますが、また新たな驚きが待っていると思うとわくわくします。この感じはrubyを初めて触ったとき以来かもしれない。非常に楽しみです。