jQueryのパフォーマンスを下げるアンチパターンに関する超意訳

以下のスライドを意訳したものです。Compress周りについては触れていません。「いやいや、最新の書き方だともっと良い書き方があるんだよ！」という方のコメントをお待ちしております！
http://www.slideshare.net/paul.irish/perfcompression

## クエリをキャッシュする

```javascript:
// 悪い例
var id = $("#content").data("id");
var itemId = $("#content").data("item-id");

// 良い例
var content = $("#content")
var id = content.data("id");
var itemId = content.data("item-id");
```

## HTMLを生成するときにjQueryオブジェクトにアクセスし続けない
```javascript:
// 悪い例
$.each(reallyLongArray, function(count, item) {
  var newLi = '<li>' + item + '</li>';
  $('#ballers').append(newLi);
});

// 良い例 : DocumentFragmentを使用
var frag = document.createDocumentFragment();
$.each(reallyLongArray, function(count, item) {
  var newLi = '<li>' + item + '</li>';
  frag.appendChild(newLi[0]);
});
$('#ballers')[0].appendChild(frag);

// 良い例 : Stringを使用
var myhtml = "";
$.each(reallyLongArray, function(count, item) {
  myhtml += '<li>' + item + '</li>';
});
$('#ballers').html(myhtml);

```

## Keep things DRY
```javascript:
// 悪い例
if ($ventfade.data('currently') != 'showing') {
  $ventfade.stop();
}
if ($venthover.data('currently') != 'showing') {
  $venthover.stop();
}
if ($spans.data('currently') != 'showing') {
  $spans.stop();
}

// 良い例
var elems = [$ventfade, $venthover, $spans];
$.each(elems, function(k, v){
  if (v.data('currently') != 'showing') {
    v.stop();
  }
});
```

## アンチパターン：オブジェクトリテラルを使わない宣言

無名関数で定義されているせいで、どこで何が起こっているのか判断がつかなくなってしまうケース。

```javascript:
$(document).ready(function() {
  ...
  $('#magic').click(function(e) {
    $('#yayeffects').slideUp(function() {
      ...
    });
  });
  $('#happiness').load(url + ' #unicorns', function() {
    ...
  });
});
```

オブジェクトリテラルを使用して記述するようにする。

```javascript:
var PI = {
  onReady: function() {
    ...
    $('#magic').click(PI.candyMtn);
    $('#happiness').load(url + ' #unicorns', PI.unicornCb);
  },
  candyMtn: function(e) {
    $('#yayeffects').slideUp(PI.slideCb);
  },
  slideCb: function() {
    ...
  },
  unicornCb: function() {
    ...
  }
};
```

オブジェクトリテラルを使用することで、下記の利点を得られる。

* コードの見通しがよくなる。
* プロファイラで関数名を参照できる。
* 各関数をコンソールで実行してみることができる。
* 無名関数のときと比べて、テストが書きやすくなる。

## アンチパターン：再クエリ

```javascript:
// create and append your element
$(document.body).append('<div class="baaron" />');
// requery to bind stuff
$("div.baaron").click(function(){ … });

// better
// swap to appendTo to hold your elem
$('<div class="baaron" />')
  .appendTo(document.body)
  .click(function(){ … });
```

## $('\#whats .the', context)

```javascript:
// パフォーマンスはこっちよりも
var arms = $('div.robotarm', '#container');
// こっちの方がいい
var arms = $('#container').find('div.robotarm');

// 読みやすさ的にはcontext？好みの問題かも。。
```

## セレクタのパフォーマンス最適化

一番パフォーマンスが良いのは\#idから下降する書き方。

```javascript:
// 普通の書き方
var arms = $('#container div.robotarm');
// もっと良い書き方
var arms = $('#container').find('div.robotarm');
```

不必要なセレクタを挟まないほうが、より高速にヒットする。

```javascript:
// 余計なものが混じっている
.data table.attendees td.gonzalez
// 中間をはぶこう
.data td.gonzalez
```

ユニバーサルセレクタはパフォーマンスを劣化させる。明示的に書いていなくても、暗黙のユニバーサルセレクタが使われている場合があるので、注意すること。

```javascript:
$('.buttons > *') // 超コストがかかる
$('.buttons').children() // 良い例

$('.gender :radio') // 暗黙のユニバーサルセレクタが含まれている
$('.gender *:radio') // 上記と同じ意味になる
$('.gender input:radio') // 良い例
```

[効率的なCSSの書き方(https://developer.mozilla.org/ja/Writing_Efficient_CSS)](https://developer.mozilla.org/ja/Writing_Efficient_CSS)

## イベントのデリゲート

live()を使うより、delegate()を使うことでより高速化できる。

```javascript:
// 汚い書き方。。
$('a.trigger', $('#container')[0]).live('click', handerFn);

// 良い書き方
$('#container').delegate('click', 'a.trigger', handlerFn);
```

## DOMの操作は総じて重い

タグのスタイル属性を直接操作するのはもってのほか。スタイルをいじりたい場合はクラスを変えよう。（DOMの操作は最小限におさえるのが原則）

## ブラックボックスとしてjQueryを扱わない

単にjQueryを隠蔽する書き方は、単に可読性を下げるだけだ。

```javascript:
// これでは単にjQueryを隠蔽しているだけで、無駄にメソッドを増やしていだけに過ぎない。。
getScript: function( url, callback ) {
  return jQuery.get( url, null, callback, "script" );
},
getJSON: function( url, data, callback ) {
  return jQuery.get( url, data, callback, "json");
},
```

よく使うメソッドは覚えておこう。

map(), slice(), stop(), (de)queue(), prevAll(), pushStack(), inArray(), etc…

```javascript:
// index() in jQuery <= 1.3.2
$('#rdworth').parent().children().index( $('#rdworth')[0] )

// prevAll()を使うと10%速くなる
$('#rdworth').prevAll().length

// jQuery1.4からはこう書ける
$('#rdworth').index()
```

## 存在しない要素に対するアクションを書かないこと

jQueryは凄く空気を読んでくれるので、そんなコードを書いたとしてもエラーは出さない・・・けど、ものすごいオーバーヘッドが裏で生じることになる。

```javascript:
$('#doesntexist').slideUp()
// genFx(), speed(), animate()といったメソッドが実行されるが、要素は存在しないため画面上では何の動きもあらわれない
```

## 便利なメソッド

### eq(), first(), last()

```javascript:
var lastelem = $elems.eq(-1); // get()と同じ

$('#nav li:first') === $('#nav li').first();
$('#nav li:last') === $('#nav li').last();
```

### data()

```javascript:
// 普通の書き方
$(elem).data(key, value);

// 10倍速い！
$.data(elem, key, value);
```