『JavaScript:The Good Parts ―「良いパーツ」

[しゃべり担当] この本、おもしろいんだ。

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

目次はこちら。http://www.oreilly.co.jp/books/9784873113913/#toc


JavaScript文法の本なんだけどさ、
この著者のコーディングスタイルは「バグを低減する」という目的のために研ぎ澄まされていて、見習う価値が大いにある、と感じたよ。ActionScriptでもほとんどそのまま当てはまるし。


この本では、やっかいな問題を抱えているので使わずに済ませるJavaScriptの機能として、以下などを挙げているよ。

==!= を使うな

==!= は使わないのがよい。変数の型が異なるとき、型キャスト(変換)をおこなうから、 0 == '0' とか ' \t\r\n' == 0 がtrueになってしまう。だから使わないのがオススメ!

===!== は同じ変数型で同じ値のときだけtrueになるのでこっちだけ使おう。


[合いの手担当] おおーいきなり飛ばすねー。これってPHPにも同じ問題があるね。PHPでも == は暗黙に型キャストするんだよ。=== なら同じ変数型で同じ値のときだけtrueになるから、PHPでも == 禁止するといいかも。


ブロックなしの文 を使うな

if(a === 1) t=true;

のように、if,while,do,forのあとを { } で囲まないのは2文字分コードを短くできるがバグ混入危険あり。なので必ず { } で囲もう。

if(a === 1){ t=true; }

[合いの手担当] これはよく言われることだね。Perlでは必ず {} が要るんじゃなかった?

ifの条件節で代入文 を使うな

ifの条件節で代入文は私はけっして使わない。
if (a = b){ .. }は、if (a === b){ .. }の書きまちがいのように見える。私は書きまちがいのように見える記述方法は使いたくないのだ。

[合いの手担当] そうだね。

これを使うとソースコードが簡潔になる(数行短くなり変数メモリが少し節約できる)代わりに、解読しにくくなるんだよね。

++ -- を使うな

使うとコードが詰まりすぎトリッキーになりすぎる。今後使わないというルールを自分に課した。i++ とは書かない。

[合いの手担当] ++i と i++ を使い分けたソース読むのは確かにイヤだね。頭をムダなことに使ってると思えてならない。
それ使わなくてもi += 1とか書けばいいからね。


Rubyでは実際++はなくて、+= 1と書くようにデザインしているし、それで問題ない。Rubyの場合は for(i=0;i<max;i++){ .. } でイテレートしなくても、 max.times do |i| .. end で済むという事情もあるけど。

ビット演算子 を使うな

JavaScriptには整数型がなく、64ビット浮動小数型しかない。だからビット演算は数値を整数に変換し、処理を行い、変数形を元に戻す処理を行なう。とても遅いので使わないほうがいい。

[合いの手担当] そうだったのか……。でもActionScript3.0なら int 型が導入されてるから、ビット演算も意味があるね。

function文 を使うな

ファンクション文 function foo() { var a=1; }
ファンクション式 var foo = function () { var a=1; }

ファンクション文は省略記法。fooは関数を値として持つ変数だと言うことがはっきり分かるという意味でも下のほうがいい。この本では下の形式だけ使っている。

[合いの手担当] ほおー。徹底してますね。これはJavaScriptならでは だなー。ActionScriptでも同じ方式にできるね。

変数型のラッパーオブジェクト を使うな

new Boolean(false)とか new Stringはどう考えても不要。new Objectとnew Arrayの利用も避けるべきである。代わりに {} と [] を使えばよい。

[合いの手担当] そうだったのか。PHPでは [] が使えないって http://d.hatena.ne.jp/kwatch/20091129/1259455757 に書いてあったな。

コメントに /* */ を使うな

コメントに /* */ を使うのは安全でない。正規表現に */ が出てきたらsyntax errorになる。 // だけ使うのが安全。

[合いの手担当] うむ、うむ。/* */ はJavaScriptでは使わなくていいね。

[しゃべり担当] ほかにも、JavaScriptでやっかいだけど避けて通れない機能、というのも この本に挙がっているよ。

ブロックスコープがない から気をつけろ

JavaScriptにはブロックスコープがない。関数内ではどこでもアクセスできる。

たとえば

var a=1;
if (a===1) {
  var b=2;
}
trace(b);

はエラーにならない。{ }ブロックに囲まれた中で宣言した変数 b がブロックの外からアクセスできる。C言語Perlならエラーになるんだけどね。

だからJavaScriptでは関数の先頭で変数を定義したほうがいい。

[合いの手担当] ふむふむ。

セミコロンを勝手に補う から気をつけろ

行末に; がない場合勝手に補う。

var a = function()
{
    ...
}

だと問題が起こりかねないので、

var a = function() {
    ...
}

のスタイルのほうがいいよ。

[合いの手担当] これは逆に、Perl, PHP等で補ってくれないのが不便に感じることあるけどな。C言語Javaみたいな堅い言語なら補ってくれないでいいけど、軽いスクリプト言語はそうでもない気がする。

Rubyセミコロンなくてもいい(ワンライナーのときは書く)けど問題ないし。JavaScriptも同じだから使い勝手のよさに貢献してると感じる。

'08' が 0 になる から気をつけろ

parseInt('08')は8進数扱いで、しかも8進数には8,9がないので、0になる。
parseInt('08',10)と基数を書くことをお勧め。

[合いの手担当] そうなのか。
ActionScript3.0では8進数サポートは廃止されて 08 が 8になるけど、ActionScript1.0は8進数があるね。

配列がニセモノだ から気をつけろ

JavaScriptの配列は使い勝手がよく、境界エラーもない。
しかし、本物の配列ではないので、実行速度が遅くなることがある。
typeofでは配列かオブジェクトか区別できない。

[合いの手担当] ActionScript3.0(ただしFlash10以降)では Vector型という本物の配列が導入されたよ。それ以前のActionScript1.0とかJavaScriptのは確かに単なる配列ではないね。

//配列
var a = ['atom' , 1, 'guitar'];
trace(a[0]);
//ハッシュ
var s = { "first-name":"永田",
          "middle name":function(arg){return typeof arg === 'number' ? arg + '号' : '17号'},
          last_name: '太郎'};
trace(s['first-name'] + s.['middle name'] + s.last_name);

a[0] だけじゃなくて、a['name'] も使えるし、a['name']は a.name とも書ける。
「配列・ハッシュ・オブジェクトのプロパティ」が文法的にいっしょくたに なってるんだよね。


[しゃべり担当] ちなみに a.nameには文字列や数値だけでなく、関数も入れることができるぞ。


PHPでも配列とハッシュがいっしょという問題はある。

$fruits = array('リンゴ'=>'椎名林檎', 'みかん'=>'Orange Range', 3, 10);
print '私の果物は' . $fruits['リンゴ'] . $fruits[1] . "\n";

が配列&ハッシュ。


Perl5は厳密に(カッコと @% を)使い分けないとならない。

@a = (1, 'monday', $b); print $a[1]; #配列
%a = {'js'=>'JavaScript', 'rb'=>'Ruby'}; print $a{'rb'}; #ハッシュ


Rubyは参照するときは同じ文法でアクセスできるけど、定義するときは別の文法を使うね。

a = [1, 'sunday', $b]; puts a[1]; #配列
a = {'as3'=>'ActionScript3.0', 'j'=>'Java'}; puts a['j']; #ハッシュ

false と判定される値が多い から気をつけろ

以下が false と判定される。

0           Number
NaN         Number
''(空文字列) String
false       Boolean
null        Object
undefined   Undefined

[合いの手担当] あー、ちょっと多いね。使い分けるのは たいへんだ。undefinedやNaNは、nullに統合してくれてもいいのにね。

グローバル変数 に気をつけろ

JavaScriptでは、関数名がグローバル領域に置かれてしまうんだ。
Javaでいうpackageがないということ。

グローバル変数は以下の方法で作れる。

  1. 関数の外で var a=1;
  2. グローバルオブジェクトにプロパティを直接追加する window.a = 1;
  3. 変数を定義せずに使う a=1; (暗黙のグローバル変数)

グローバル関数の利用を最低限にするには、

var ctnr = {}; //変数をコンテナとして使う
ctnr.obj = { first_name:who, last_name : Hwd};


この本では他に、配列関連、文字列関連、正規表現などを説明している。DOM操作とか外部ライブラリの説明は特にない。


あと、関数のクロージャやモジュール作成、プロトタイプ、継承 等も説明されている。これはまた学習したい。


参考:

JavaScript 第5版

JavaScript 第5版