TDD で jQuery plugin を作ってみた

指定した element のサイズに合わせて 1 行ごとにフォントサイズを調整する jQuery のプラグインを書いた。結果はサンプルを見た方がわかりやすいと思う。

指定したフォントや、使っている文字とブラウザの組み合わせによっては、上手くサイズが合わなくて折り返しちゃったりする事があるので、完璧ではないけど。。一応、Mac の Safari、Chrome、Firefox でテストした。

これを作る前に テスト駆動JavaScript を読んでたので、JsTestDriver のテストを書きながら作ってみた。

ちょっとハマったのが、JsTestDriver の charset が iso-8859-1 で決め打ちされてるので、日本語のテストができなかった。一応 Accepted になってる からいつかは直ると思うけど、結構放置気味…。

TDD を初めて自分でやってみたんだけど、テストを先に書く良さというのが (説明はできないまでも) 何となく体感できたような気がする。

後は、JsTestDriver のテストは、”test…“ で始まらないものが無視されるようなので、考えた仕様をメモ的に “should ….” とかで空のテストとして思いついたものから書いておいて、1 つづつ順番にテスト → 実装を繰り返すようなこともした(邪道かもしれないが)。

TDD で jQuery plugin を作ってみた

Foundation フレームワーク

Twitter の Bootstrap が人気みたいだが、Wireframes Magazineで同じようなフレームワークの Foundationというのが紹介されていた (MIT License)。

UIのコンポーネントとしては一通りのものがそろっている。特徴は responsive design に対応しているところ。以下のサイトにレビューやコメントがある。

好みにもよるが、ネガティブなコメントもあった。例えば、

  • Form のスタイルはクラスで指定するのではなく、全体に適用される
  • normalize じゃなくて reset している
  • モバイル向けにコンテンツの一部を隠したりするのを CSS ベースで行っているので、読み込み自体はされてしまっている
  • イメージのリサイズについても同様

まあ Rapid Prototyping and Building Framework とあるように、細かい部分まで考慮するなら、いろいろカスタマイズしてサーバ側のスクリプトも使ったり、複数の画像を用意したりする必要があるのかも知れないが、デモページをいくつかブラウザのウィンドウサイズを変えながら見たりした限りでは、なかなか便利そうだった。例えばこれ

Foundation フレームワーク

JavaScript の関数呼び出しと this

Yehuda Katz のブログで 2011/08/11 に post された記事 の概要。

大本の関数呼び出し

Function の call メソッドは次のように動作する

  1. すべての引数のリストを作る (argList)
  2. 最初のパラメータが thisValue
  3. function が this を最初の引数、次の引数に argList を指定して呼び出される

例:

   function hello(thing) {
     console.log(this + " says hello " + thing);
   }

   hello.call("Yehuda", "world") //=> Yehuda says hello world

他の呼び出し方は、この形式に変換できる。

単純な関数呼び出し

例:

   function hello(thing) {
     console.log("Hello " + thing);
   }

   // これは:
   hello("world")

   // このように変換できる:
   hello.call(window, "world");

ECMAScript 5 (ES5)の strict モードでは、 hello.call(undefined, “world”) になる。

メンバ関数

例:

   var person = {
     name: "Brendan Eich",
     hello: function(thing) {
       console.log(this + " says hello " + thing);
     }
   }

   // this:
   person.hello("world")

   // desugars to this:
   person.hello.call(person, "world");

hello メソッドがどのような方法でオブジェクトにアタッチされているかは関係ない。動的に追加された場合を見ると、次のようになる。

   function hello(thing) {
     console.log(this + " says hello " + thing);
   }

   person = { name: "Brendan Eich" }
   person.hello = hello;

   person.hello("world") // これも person.hello.call(person, "world") と同じ意味になる

   hello("world") // これは "[object DOMWindow] says hello world" となる

Function.prototype.bind を使った場合

常に同じ this を持つように、closure を使うテクニックが良く使われる。

   var person = {
     name: "Brendan Eich",
     hello: function(thing) {
       console.log(this.name + " says hello " + thing);
     }
   }

   var boundHello = function(thing) { return person.hello.call(person, thing); }

   boundHello("world"); // "Brendan Eich says hello world"
</code></pre>
このテクニックをもう少し汎用的にして、次のように書くことができる。
<pre><code>   var bind = function(func, thisValue) {
     return function() {
       return func.apply(thisValue, arguments);
     }
   }

   var boundHello = bind(person.hello, person);
   boundHello("world") // "Brendan Eich says hello world"

これを理解するためのポイントは、arguments は配列に似たオブジェクトだということと、apply メソッドは引数を配列に似たオブジェクトとして扱う以外は call メソッドと同じだということ。

尚、ES5 には Function に bind メソッドが追加されている。

   var boundHello = person.hello.bind(person);
   boundHello("world") // "Brendan Eich says hello world"

これはもとの関数をコールバックとして渡す時に便利である。

   var person = {
     name: "Alex Russell",
     hello: function() { console.log(this.name + " says hello world"); }
   }

   $("#some-div").click(person.hello.bind(person));

   // div がクリックされたら、 "Alex Russell says hello world" が表示される
JavaScript の関数呼び出しと this