『Effective JavaScript』を読んで(項目1~3)

いつだったか翔泳社Kindle セールをやっていて、目にとまった『Effective JavaScript JavaScriptを使うときに知っておきたい68の冴えたやり方』を購入して読んでいる。

 

 

大学の研究や仕事で JavaScript さんとふれあう機会はあったのだけど、いまいち理解してない感じで、コーディングしていていつももやもやしていた。仕事でぱぱーっとコーディングしてるだけでは、挙動が分からな いという奥深さ(意味不明さとも言うのかも)に興味を持っていたので、非常に楽しく読んでいる。「なんか JavaScript って Lisp に近いモノを感じるなぁ」と最近思っていたんだけど、さらにその思いは強くなった(Lisp 大して知らないけど)

せっかくブログを始めたし内容をメモしておこうと思う(すぐ忘れるし)。幸い、この本は項目に別れて書かれていメモしやすい。

 

第一章:JavaScript に慣れ親しむ

項目1:どの JavaScript を使っているのかを意識しよう

その名の通り。歴史的?政治的?経緯から、巷にいろいろな JavaScript 実装があふれているので、どのバージョンの仕様向けなのか、どの実装向けなのか、意識して書くようにしよう。

できれば strict モードを使う。strict モードを有効にする strict ディレクティブ("use strict;")は、ファイルの先頭か関数の先頭でしか認識されない(変数スコープの挙動に近い)。この性質のために、複数の js ファイルを連結すると問題が起こる場合がある。そのため、即時関数式(IIFE, Immedeiately Invoked Function Expression)で包んでローカルスコープを作った方がいい。

// file1.js
function() {
    "use strict";
// ... code ... }();

ちなみに、strict ディレクティブが文字列なのは後方互換性のため。strict ディレクティブが実装されていない JavaScript 実装の場合では文字列を評価するだけなので問題が起こらない(こういう後方互換性への思いやりの精神は大事にしたい)

項目2:JavaScript浮動小数点数を理解しよう

 JavaScript にいわゆる Int 型はない。数を表すのは Number 型で中身はIEEE754 の倍精度浮動小数点数である(いわゆる Double 型)。

ちなみに、倍精度浮動小数点数は 53 ビット精度の整数を表現することができる。IEE754 の倍精度は、

  • 符号:1ビット
  • 指数部:11ビット
  • 仮数部:52ビット

なので、仮数部と符号ビットを利用して 53 ビット精度の整数が表現できる(小数点位置53 桁の移動は11ビット内で表現できるし)。一つ前の記事で「以前、調べたときに『64 bit 浮動小数数点数で 64 bit 整数のすべてを表現できる』って結論付けたの間違いだな」って書いたけど、『32 bit 整数のすべてを表現できる』って結論付けたことを思い出したので、昔の俺は間違ってなかった。

ビット毎の数値演算を行うときは「ビッグエンディアンの2の補数表現(いわゆるInt 表現)」に変換されてから演算が行われる点に注意する。ビット毎の数値演算しか行われない変数は、最適化のため内部的に Int 表現で保持されていたりするらしい。

項目3:暗黙の型変換に注意しよう

 JavaScript演算子に合うように値の型を勝手に変換してくる。この動作を『型に値を強制(coerce)する』という。変換規則が細かくて、いちいち覚えてられないので、邪悪そうな実例と根拠だけ列挙しておこう。

3 + true; // => 4

true が Number 型の 1 に変換されるので 4 になる

1 + 2 + "3"; // => "33"

加算は左結合なので、1 + 2 => 3。Number と String の加算では Number が String に強制されるので 3 + "3" => "33" になる

1 + "2" + 3; // => "123"

1 + "2" => "12" となり、"12" + 3 となる。3 は String に強制されるので "123" になる

めんどくさいのが NaN。IEEE の Not a Number に対応している値。規格上の定義が「それ自身と等しくない値」なので、

var x = NaN;
x === NaN // => false

となる。標準の isNaN() もあてにならない(Nan に型を強制してしまう)ので、NaN かどうかを調べるには「自身と比べて等しくない」という性質を利用する。

var x = NaN;
x !== x // -> true

オブジェクトはたいてい String か Number に型を強制される事が多く、その際、toString() と valueOf() が呼ばれる。ただし、そのオブジェクトがどちらに値を強制されるかは不明(プロパティ順だったか?知っていたら教えてほしい)。

最後はブール値に値が強制される話。以下の値はすべて false に強制される。逆に下記以外はすべて true となる。

false, 0, -0, "", NaN, null,  undefined

0 や "" が false と評価される点に注意しなければならない。以下のようにして isUndefined を定義すると 0 や "" が undefined として判定されてしまう

define isUndefined(x) {
   return !x
}
isUndefined(1); // => false
isUndefined(undefined); // => true
isUndefined(0) // => true
isUndefined(""); // => true

 

ほんとうは3章の途中まで読み終わっていて、1章のまとめを書きたかったのだけど疲れたのでここまで。なるべく、小さいことを積み重ねて大きくしていこうと思う。