Secret of the JavaScript Ninja 3章を読んだ
2章に続いて3章を読み合わせました。
ちなみに、2章で使ったassert()がほぼ全てのコードで使われているので、サンプルコードを試したい方はライブラリ化しといた方がいいと思われます。
3章は関数について。
JavaScriptは関数型言語なんだよ、関数はファーストクラスでオブジェクトみたいに扱えるよ。
関数の中でも匿名関数(anonymous function)は最重要だよ。理解できたら綺麗で再利用しやすいコードが書けるようになると思うよ!的な。
で、匿名関数にかなりのページが割かれてます。
匿名関数というのは無名関数とも呼ばれますが、この本では「名前を持つ必要がない関数」と定義しているようです。
anonymousってあるけど、namelessとした方がいいのかな・・
オブジェクトのプロパティやイベントハンドラ、コールバックなんかでいきなり定義するfunctionはどれも匿名関数。
さりげなく再帰のコード例で「arguments.callee」が出てきました。
匿名関数で再帰をするときは「arguments.callee」使うと綺麗に書ける。
その後は、関数にもオブジェクトみたいにプロパティを追加できるよとか、関数内のコンテキストオブジェクト(this)を書き換えたければ「call() or apply()」を使えばできるよという話が続きます。
分かりやすかったのが、"Fake Array Methods"の件。
lengthプロパティを追加したオブジェクトにはArrayメソッドを利用できる。
var elems = { length: 0, add: function(elem) { Array.prototype.push.call(this, elem); } };
例えばオブジェクトに要素を突っ込みたいときなど、lengthプロパティを付ければ、配列用のメソッドをthisを書き換えることで利用できるようになって便利という話。
今回一番勉強になったのは、JavaScriptでのオーバーロードのやり方。
function addMethod(object, name, fn){ var old = object[ name ]; object[ name ] = function(){ if ( fn.length == arguments.length ) return fn.apply( this, arguments ) else if ( typeof old == 'function' ) return old.apply( this, arguments ); }; } function Ninjas(){ var ninjas = [ "Dean Edwards", "Sam Stephenson", "Alex Russell" ]; addMethod(this, "find", function(){ return ninjas; }); addMethod(this, "find", function(name){ var ret = []; for ( var i = 0; i < ninjas.length; i++ ) if ( ninjas[i].indexOf(name) == 0 ) ret.push( ninjas[i] ); return ret; }); addMethod(this, "find", function(first, last){ var ret = []; for ( var i = 0; i < ninjas.length; i++ ) if ( ninjas[i] == (first + " " + last) ) ret.push( ninjas[i] ); return ret; }); } var ninjas = new Ninjas(); assert( ninjas.find().length == 3, "Finds all ninjas" ); assert( ninjas.find("Sam").length == 1, "Finds ninjas by first name" ); assert( ninjas.find("Dean", "Edwards").length == 1, "Finds ninjas by first and last name" ); assert( ninjas.find("Alex", "X", "Russell") == null, "Does nothing" );
addMethod()を呼ぶたびに、同じ名前で追加されている関数をold変数に突っ込んでいってます。
old変数の中身を見ると・・・
- 1回目のaddMethod()時のold変数
undefined
- 2回目のaddMethod()時のold変数
var old = function(){ if ( fn.length == arguments.length ) // fnは1回目で登録された匿名関数 return fn.apply( this, arguments ) else if ( typeof old == 'function' ) // oldは'undefined'なのでスルー return old.apply( this, arguments ); };
- 3回目のadd()時のold変数
var old = function(){ if ( fn.length == arguments.length ) // fnは2回目で登録された匿名関数 return fn.apply( this, arguments ) else if ( typeof old == 'function' ) // oldは2回目のaddMethod()時のold変数 return old.apply( this, arguments ); };
引数の数をチェックして、falseならそれより前に登録された関数でもっての引数の数をチェックして・・・
という感じでオーバーロードを実現しています。
おおー確かにこうやればできるね!奥が深い。
ただ、関数呼び出しのオーバーヘッドが大きいので、パフォーマンスが求められる場合は注意してねとのこと。
最後は関数かどうかのチェック方法について。
「Object.prototype.toString.call(arg)」でおk。jQueryもそうなってますしね。
これは既にライブラリ化済みだぜ!
サンプルコードを見る限りでは、ここまでが序の口で4章のクロージャから難しくなってきそうです。
Secret of the JavaScript Ninja 2章を読んだ
d:id:ojimacと定期的に読んでいくことになった。
一緒に読みたい!という人がいれば気軽にTwitter(@cheesepie)で声かけてください!
2章はデバッグの基本(ロギングとブレークポイント)とテストケースについて。
ロギングはまあconsole.logをクロスブラウザ化して使いましょう、ブレークポイントはブラウザのコンソール使ってやっていきましょうてな具合で。
テストケースは3つのポリシーを守るべし。
- テストは高い再現性を持つべし
- テストは出来る限りシンプルにするべし
- テストはテスト同士が依存しないように最小単位のテストに分割するべし
単体テストフレームワークとして、QUnit/YUITest/JSUnitが紹介されています。
JSUnitはメンテされてないので、モダンブラウザでのテストにはちょっと不安が。
個人的にはGoogle Closure Libraryのテストフレームワークが一番好みです!
で、既存のテストフレームワークを使った方がよさげなんだけど、どういう動きをしているのかを理解しておくのはいいことだよね。
ということで、テストフレームワークの基本要素となるAssertion/Test Groups/Asynchronous testingの3つがどういう仕組みになっているかをシンプルなコード例とともに説明しています。
それぞれ40行くらいで書けちゃうんだぜとはResig殿の弁。
非同期テストのサンプルが分かりやすかった。
(function() { var queue = [], paused = false, results; this.test = function(name, fn) { queue.push(function() { results = document.getElementById("results"); results = assert( true, name ).appendChild( document.createElement("ul") ); fn(); }); runTest(); }; this.pause = function() { paused = true; }; this.resume = function() { paused = false; setTimeout(runTest, 1); }; function runTest() { if ( !paused && queue.length ) { queue.shift()(); if ( !paused ) { resume(); } } } this.assert = function assert( value, desc ) { var li = document.createElement("li"); li.className = value ? "pass" : "fail"; li.appendChild( document.createTextNode( desc ) ); results.appendChild( li ); if ( !value ) { li.parentNode.parentNode.className = "fail"; } return li; }; })(); window.onload = function() { test("Async Test #1", function() { pause(); setTimeout(function() { assert( true, "First test completed" ); resume(); }, 1000); }); test("Async Test #2", function() { pause(); setTimeout(function() { assert( true, "Second test completed" ); resume(); }, 1000); }); };
このテストがどういう流れで処理されるかというと・・・
- Async Test #1のtest()が実行される
- キューにAsync Test #1のtest()の引数で渡された関数が入る
- runTest()
- キューから先ほど入れられた関数を取り出し実行する
- pausedをtrueにする
- Async Test #2のtest()が実行される
- キューにAsync Test #2のtest()の引数で渡された関数が入る
- runTest()
- !pausedがfalseを返すので何もしない
- Async Test #1のsetTimeoutで指定された関数が実行される
- "First test completed"をHTMLに書き出す
- pausedをfalseにし、runTest()
- キューからAsync Test #2のtest()の引数で渡された関数を取り出し実行する
- pausedをtrueにする
- Async Test #2のsetTimeoutで指定された関数が実行される
- "Second test completed"をHTMLに書き出す
- pausedをfalseにし、runTest()
- キューには何も入っていないので終了
キューとpause()とresume()を使うことで、非同期であっても必ず「#1のテスト→#2のテスト」という順番でテストが実行されるようになる。
これで3つのポリシーでも挙げられていた「テストは高い再現性を持つべし」を実現できるということか。
いやー勉強になります。
最後まで読んでみないと分かりませんが、Secret of the JavaScrpt Ninjaはサイ本と並んでオススメできるかも。
書籍の発売日は8月なのですが、PDF版は先行して購入できます。
PDF版もまだ14章までしかありませんが、章が追加されたり更新されるたびに新しいPDFを受け取れるようになっています。
Secrets of the JavaScript Ninja
- 作者: John Resig,Bear Bibeault
- 出版社/メーカー: Manning Publications
- 発売日: 2013/01/17
- メディア: ペーパーバック
- 購入: 1人 クリック: 353回
- この商品を含むブログ (16件) を見る
XMLHttpRequestのステータスコードが0になるケース
XMLHttpRequestのステータスコードが0になるケース。
1. プロトコルがftpやfileなどhttp以外の場合
→例えば、ローカルでhtmlファイル開いて実行したりするとステータスは"0"になる
2. Webサーバーがリクエストを送る時点で落ちていた場合
w3.orgに仕様として、0を指定することとある
http://www.w3.org/TR/XMLHttpRequest/#error-flag
3. 古いOperaでは「204/304/504」が0として扱われる
http://leaf.argyr.net/javascript/xmlhttprequest-response/
2のケースが起きた場合、判定する術がない。。。
responseTextが空?いや200で空のときもありえるし(そもそも204 No Content返すべきだろうけど)。
なので、「200/204/304」なら成功、それ以外(0も含む)はエラーとして扱うのがいいかな。
あけましておめでとうございます
今年は...
- 仕事
- とにかく作る
- 絶対リリース
- 仕事外
- サービスを作る!
- 時間を上手くやりくり
- 勉強会とか外に出る
本年もよろしくお願いいたします。
Yii
なんつー強引な。
任天堂が「Zii」「Oii」「Pii」「Qii」「Uii」「Yii」を商標登録していた
2006年に既に登録してたのね。キーボード配列的に「Qii」はありえるかも。
PHPのフレームワークの方も忘れないであげてください。
Yii PHP Framework: Best for Web 2.0 Development
音楽プレーヤーの方も。
Zii.com