jQueryの汚染をなくした上で、$を使ったパフォーマンスベンチマーク

jQueryの話を社内ブログの方に書いたのだけど、よくよく考えてみたら僕が外から見れないなと。
ってことでこっちにも同じ内容。
# 自分がばれそうなところは変更。
# って言っても社内の人にはばれるのか。


jQueryを使いながらJavaScriptを書いているのだけど、
ユーザ向けに、なるべくグローバル変数を汚さないようにしようと、
jQueryで使われるグローバル変数jQuery」と、そのショートカットの「$」を
「A.B.dom」にしようとした。
こうすればユーザの「$」は生きるし、Aのみグローバル変数を汚すだけなので。


で、ある程度までできあがったものの、「$」で済むところが、
「A.B.dom」になってるから正直見にくい。


ということでやり直し。
クロージャを使ってA.B.domを$に代入して全体を書いてみようかなと。
# まぁ、あんまりクロージャわかってないから嘘言ってるかもしれないけど。


で、関数を超えて変数を参照するから重くなるかな?と思い、
一応ベンチマーク
# ベンチマークの関数は404 Blog Not Found:javascript vs perl - プライベート変数による初期化のを使わせていただきました。


で、実験。
やりたいことは、
1.グローバルは「A」って変数しか汚さない
2.今まで「A.B.dom」だった部分を「$」に変更して実行できるか。
ってところだけなので、下のような関数書いてみた。
これが上手く動けば2.の確認OK。

/*
 * $ を使い回す
 */
(function(){
    window.A = {};
    window.A.B = {};
    window.A.B.dom = jQuery.noConflict(true); // 汚染回避

    var $ = window.A.B.dom;
    $.fn.extend({
        a : function (id) {
            for (var i=0; i<1000; i++) {       // 1000回 $ を参照
                if ($) continue;
            }
            return $(id).html('jquery');
        }
    });
})()

/*
 * A.B.dom を使い回す
 */
A.B.dom.fn.extend({
  b : function (id) {
      for (var i=0; i<1000; i++) { // 1000回 A.B.dom を参照
          if (A.B.dom) continue;
      }
      return A.B.dom(id).html('jquery');
  }
});


で、jQueryを呼び出す前に以下の2つを宣言しておいて、
最後にこの2つがちゃんと呼び出せれば1.の確認はOK。

window.jQuery = {p: 'jQueryプロパティ'}; // 仮想jQuery
window.$ = {p: '$プロパティ'}; // 仮想$


結果。
上が関数aの実行時間で、下が関数bの実行時間。
案外$にした方が速かったという結果になってしまった。
ドット演算ってそんなに遅いのね。今まで書いてたやつ修正しないとかな。
ってか、やっぱりFirefox3Beta5とSafari3.1は速ぇなー。
ソースは下の方に。

  • IE6 standalone
    • 250ミリ秒
    • 719ミリ秒
  • IE7
    • 250ミリ秒
    • 891ミリ秒
  • IE8
    • 297ミリ秒
    • 1094ミリ秒
  • lolifox 0.3.2
    • 313ミリ秒
    • 594ミリ秒
  • Firefox 3Beta5
    • 73ミリ秒
    • 85ミリ秒
  • Opera 9.24
    • 94ミリ秒
    • 141ミリ秒
  • Safari 3.1
    • 63ミリ秒
    • 125ミリ秒
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <script type="text/javascript">
window.jQuery = {p: 'jQueryプロパティ'}; // 仮想jQuery
window.$ = {p: '$プロパティ'}; // 仮想$
</script>
  <script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
   
<script type="text/javascript">
// ベンチマーク関数
// from http://blog.livedoor.jp/dankogai/archives/50968466.html
function benchthis(count, func){
  var args  = [];
  for (var i = 2, l = arguments.length; i < l; i++)
    args[args.length] = arguments[i];
  var timer = (new Date()).getTime();
  for (var i = 0; i < count; i++) func.apply(this, args);
  return (new Date()).getTime() - timer;
}
// 出力
function p(output) {
    document.getElementById('result').innerHTML += output + 'ミリ秒<br />';
}

/*
 * $ を使い回す
 */
(function(){
    window.A = {};
    window.A.B = {};
    window.A.B.dom = jQuery.noConflict(true); // 汚染回避

    var $ = window.A.B.dom;
    $.fn.extend({
        a : function (id) {
            for (var i=0; i<1000; i++) { // 1000回 $ を参照
                if ($) continue;
            }
            return $(id).html('jquery');
        }
    });
})()

/*
 * A.B.dom を使い回す
 */
A.B.dom.fn.extend({
  b : function (id) {
      for (var i=0; i<1000; i++) { // 1000回 A.B.dom を参照
          if (A.B.dom) continue;
      }
      return A.B.dom(id).html('jquery');
  }
});

    </script>
</head>
<body>
  <div id="test1"></div>
  <div id="test2"></div>
  <hr />
  <div id="result"></div>
  <script type="text/javascript">
p(benchthis(100, A.B.dom().a, '#test1'));
p(benchthis(100, A.B.dom().b, '#test2'));

document.getElementById('test1').innerHTML = jQuery.p;
document.getElementById('test2').innerHTML = $.p;
  </script>
</body>
</html>