どうもひろきのだいちです。
水野さん。ありがとう。こんないい本を訳してくれて。そしてくれて。

この本はJavaScriptの世界を一段押し上げるためのものです。きっとJGPとか略されたり、蝶本といわれたりとしてこれからJavaScriptの世界でスタンダードとなる概念を構築するための本になるんだろうなと。その意味では仕事でJavaScriptを読む人間に必携の本となるだろうし、この本を「読む」だけではなくて「理解」することが必須となる本となるだろう。
しかし、これはPerlの世界で言うところ「Perl Best Practices」的な書籍ではないということも理解してほしい。
というのもまだ、JavaScriptの世界はPerlほど成熟していないからだ。
この本は「use strict」「use warnings」のための諸概念を切り出すという段階を担っているものであり、
JSLintはその外部実装といったほうがいいのだろうか。
これが荒唐無稽な著者の挑戦でないことは彼がすでに「JSONの規格化」に成功していることからも伺える。
次の段階を考えてみよう。
良いものと悪いものの線引きはできた。
ではその次は悪いものの使いどころと悪い性質の避け方だ。
Perlには「no strict」「no warnings」が用意されていて、悪い面をライブラリユーザに見せずに清潔なプログラミングを可能にしている。
newの使いどころ
newの何がわるいの?
JAVASCRIPT:
-
function hoge(){
-
this.fuga = "x";
-
}
-
new hoge(); //{fuga:"x"}
newはjavascriptのクラスシステムの根幹を担うところであり、使わないという選択肢はなかなか難しい。
すべての機能をmethod chainの中に隠蔽してしまうという方法論もあるにはあるが、DOMありきのプログラミングモデルならまだしも、それ以上のものを考える場合には必要最低限の機能である。
なにが悪いのかといえば次のようなケースである。
JAVASCRIPT:
-
function hoge(){
-
this.fuga = "x";
-
}
-
hoge(); // undefined, window.fuga="x"
hogeはコンストラクタなのに、new演算子を伴わないで呼び出された場合にfunctionにbindされているthisかあるいはトップレベルオブジェクトに対して汚染をしてしまうケースがある。
これは確かに致命的だ。
ひとつはコーディングルールの中にClass名をHogeのように先頭をcapitalizeするという方法論だ。
もうひとつはコンストラクタ中でチェックルーチンを入れるという方法論。
JAVASCRIPT:
-
function Hoge(){
-
if(this===self)throw('Error');
-
this.fuga = "x";
-
}
-
Hoge(); // error :Error
あるいは、
JAVASCRIPT:
-
function Hoge(){
-
if(this.constructor!==Hoge)throw('Error');
-
this.fuga = "x";
-
}
-
var x ={};Hoge.apply(x);
こういった機能の柔軟性を封じるやり方もできる。
本書に出てくるnewをFunctionオブジェクトのmethodとして実装するやり方もエレガントだけど、
もうすでにnewがあるんだからライブラリ作成者なりが注意しておくか、レビューをしっかりすれば問題ナッシングだと思う。
withの使いどころ
JavaScriptからは関数のスコープで定義されるActivation Objectに直接アクセスすることができない。
これはここらへんを読んでもらうとして。
たとえば、Globalオブジェクトをできる限り汚染しないようにして、ネームスペース的機能を提供しようとした場合に
JAVASCRIPT:
-
window['core'] = {};
-
(function(){with(this){
-
this.fuga = 'text';
-
}}).apply(window['core']);
-
-
(function(){with(this){
-
print(fuga);
-
}}).apply(window['core']);
これは適切なnamespace機能さえjavascriptに用意されていれば済む話だが、withが強力な機能を提供する場面でのひとつだ。
eval/new Functionの使いどころ
evalはあらゆる言語で悪者だ。
パフォーマンスを下げてしまうし危険を伴うと紹介されることがおおい。
これに関しておおむね同意した上でもなお、evalを利用することが適切な場面が存在する。
これは皮肉なことにむしろパフォーマンスの分野で。
Webクライアントの技術において、パフォーマンスとはユーザエクスペリエンスのために存在する。つまりユーザがある動作(クリックなど)を行ってから何らかのアクションが発生するまでの時間を最適化したいというニーズが最も多い。
なので、
JAVASCRIPT:
-
element.onclick = function(){
-
for(var i=0,length=BIG_ARRAY.length;i<length;i++){
-
//複雑な条件や分岐により重くなる処理
-
}
-
}
のようなプログラムがあったときに
JAVASCRIPT:
-
dom.ready(function(){
-
try{
-
window.onclick = new Function([
-
'複雑な条件、分岐処理で確定しているものを取り除いたtext'
-
].join(''))
-
}catch(e){}
-
});
のようにしておくことで、DOM構築完了後からimageロードまでの比較的余裕のある時間でスマートな関数を構築しておくことができる。
こういったテクニックは邪道ではあるが、effects.jsなどでも用いられている高速化テクニックの1つであって、JavaScriptというインタラクションのために用いられる言語では重要な要素になりうる。
あくまでもミッションクリティカルな場所でのみ使われるべきではあるが、Templateエンジンなどを実装するためにはevalという邪悪な手段が最適最良のスマートな方法になる。
function文とfunction式
function文とfunction式の違いは、Activationオブジェクトの生成タイミングを理解しておけば間違えることは少ないだろうが、解釈の違いにより問題が起こることは確かにある。
JAVASCRIPT:
-
//function 文
-
function hoge(){
-
[sample code];
-
}
-
//function 式
-
var hoge = function(){
-
[sample code]
-
}
これらは同値であると説明される場合が多いが以下のようなケースで違いが発生する。
JAVASCRIPT:
-
(function(){
-
var x = 0;
-
console.log(hoge);// function hoge(){}
-
function hoge(){}
-
})();
-
-
(function(){
-
var x = 0;
-
console.log(hoge);//undefined
-
var hoge=function(){}
-
})();
function文は自動的にスコープの先頭に移動して解釈されるが、function式は解釈されない。
これ自体は小さな問題に見えるが、さらにif文内でのfunction文の巻き取りはjsの実装によって異なりポータビリティを損なうというのが本書の指摘するところだ。
たしかにこれらはポータビリティや保守性を下げる場合がおおい。
しかし、function文がデバッグ性にプラスの要素を与える場合が実はある。
JAVASCRIPT:
-
Handler = {
-
func : (function(){
-
function xxx(){}
-
return xxx;
-
})()
-
}
-
console.log(Handler.func); // xxx
-
-
Handler = {
-
func : (function(){
-
var xxx = function(){}
-
return xxx;
-
})()
-
}
-
console.log(Handler.func); // function
function文によって作られた関数は処理系内部において"公式な名前"を得ることができる。
公式な名前がある関数は、それが他の関数ではなくて自分自身であることを証明することができる。
この仕様を正式なものとしてなにかプログラムを書くことを推奨はしないが、
この要素が煩雑なプログラムの中で問題箇所を適切に見つけることのできる一因になることがあるということは覚えておいて損はないだろう。
functionは式であれ、文であれこの"公式な名前"をつけられるという性質を知っていると
プロファイル等で
JAVASCRIPT:
-
$('test').observe('click',function (){
-
// 公式な名前の無い関数
-
});
-
-
$('test').observe('click',function _anon(){
-
// 公式な名前のある関数
-
});
複数の無名関数の中から、問題の箇所をわずかな変更ですぐに知ることができるかもしれない。
これらはfunction文ではなく、function式であるのでスコープのオブジェクトを汚染することはない。
JAVASCRIPT:
-
$('button').observe('click',function _anon2(){
-
$w('first last').each(function _anon(e){
-
//
-
});
-
console.log(_anon); //is not defined
-
});
-
console.log(_anon2); //is not defined
公式に運用するscript中では無用なものではあるかもしれないが、こういった性質によって見えてくる世界もある。
そんなわけでまとめ
・JavaScript Good Partsは仕事でJavaScriptを書くすべてのエンジニアが必読の書である。
・読んだ後、汚いもの/悪いものがどのように使われるべきか考えてみよう
・きれいな世界と汚い世界を分けることでJavaScriptはもっと輝きを増す。