Archive for the "javascript" Tag
for Loop
JavaScriptのfor文の書き方のテスト。
配列の先頭から末尾までの繰り返しを行う
単純な場面を想定してみる。
for (var i = 0; i < items.length; i++);
書き方1(以下、for1)
配列の長さ分繰り返す、よく見かける書き方。
for (var i = 0, ix = items.length; i < ix; i++);
書き方2(以下、for2)
最初に配列の長さを保持して、
条件式の計算量を抑える書き方。
for (var item, i = 0; item = items[i]; i++);
書き方3(以下、for3)
条件式で配列の要素の代入をそのまま判定に使う書き方。
要素が偽になり得る配列には使えない。
while的な書き方。
それぞれを関数で包んで、
Firebugで次の様なパフォーマンステストしてみた。
配列の長さとコール数のバランスによって結果は変わりそうだけど、
まあ、適当に。
function for1 (items) {
for (var i = 0; i < items.length; i++);
}
function for2 (items) {
for (var i = 0, ix = items.length; i < ix; i++);
}
function for3 (items) {
for (var item, i = 0; item = items[i]; i++);
}
var data = [];
for (var i = 0; i < 1000; i++) data.push({ n: i, s: '', d: new Date });
console.profile('profile');
for (var i = 0; i < 1000; i++) for1(data);
for (var i = 0; i < 1000; i++) for2(data);
for (var i = 0; i < 1000; i++) for3(data);
console.profileEnd();
for文だけの処理時間の結果は、
for3 (45%) > for1 (35%) > for2 (15%)
大体、こんな感じで、
for2 は for1 よりも条件式の計算の差で若干速い。
for3 は変数代入分だけコストがかかって遅い。
function for1 & for2 (items) {
for (...) {
items[i].n; items[i].s; items[i].d;
}
}
function for3 (items) {
for (...) {
item.n; item.s; item.d;
}
}
次に、配列の要素の中身を参照する処理を加えてテスト。
for1 (35%) = for2 (35%) > for3 (30%)
結果は大体、こんな感じで、
for1 と for2 にそこまでの差は無くて、
アクセスする階層が深いので、当然遅くなる。
一旦変数に入れれば for3 と同じだけど、
書き方は for3 が綺麗かなと思った(whileよりも繰り返し条件が見やすいし)
ちょっと複雑になると気付くのだけど、
単純な 0 〜 lenght になると愚直に for1 や for2 を書いちゃうんだよね〜
少し見直してみよう。
Class (instanceof Class)
簡易なクラス生成関数。
試してみたかった事は本格的なクラスの再現では無いので、
継承機能なんて無い。
だったら関数定義でいいじゃん。
って回りくどいのは、インスタンスからクラスを参照した時の挙動を変えたかったから。
SnipplrClass (instanceof Class)
Posted by inamorix on January 9th, 2008
- function Class (ns) {
- this.toString = function () { return ns; };
- }
- Class.def = function (ns, ctx) {
- var c = window;
- var ns = ns.split('.');
- for (var i = 0, ix = ns.length - 1; i < ix; i++)
- c = c[ns[i]] instanceof Object ? c[ns[i]] : c[ns[i]] = {};
- if (!(ctx.init instanceof Function)) ctx.init = function () {};
- c = c[ns[i]] = function () { this.constructor.apply(this, arguments); };
- c.prototype = new Class(ns.join('.'));
- c.prototype.constructor = ctx.init;
- for (var key in ctx) if (ctx.hasOwnProperty(key)) {
- if (key != 'init') c.prototype[key] = ctx[key];
- }
- return c;
- };
Class.def('com.example.Rect', {
x: 0, y: 0,
init: function (x, y) {
this.x = x;
this.y = y;
},
getArea: function () {
return this.x * this.y;
},
reset: function (x, y) {
this.constructor(x, y);
}
});
r1 = new com.example.Rect(20, 30);
r2 = new com.example.Rect(100, 50);
r1.getArea(); // 600
r2.getArea(); // 5000
Class.defでクラスを定義。
第1引数に名前空間を指定。
第2引数にプロパティやメソッドのオブジェクトを指定。
initはコンストラクタ的に扱われる。
一応、定義されたクラスが戻り値。
ここまでは特に変わった事は無い。
r1 == 'com.example.Rect'; // true r2 == 'com.example.Rect'; // true r1 instanceof Class; // true r2 instanceof Class; // true r1 instanceof com.example.Rect; // true r2 instanceof com.example.Rect; // true
文字列として扱うと、名前空間で指定した文字列が返る。
instanceofでクラスを参照するとClassとして認識される。
Class.defを通して定義されたクラスは、
全てClassのインスタンスとして認識される。
定義したクラス(この場合com.example.Rect)のインスタンスとしても認識される。
厳密に型チェックしたい時は文字列で柔軟に扱えて、
大雑把にチェックする時は共通している方がシンプルなので、
文脈的に綺麗なinstanceofを多用しやすいかな。
試してみたかったのはこれ。
r2.reset(40, 20); r1.getArea(); // 600 r2.getArea(); // 800
メソッドresetはthis.constructorをコールしていて、
コンストラクタはinitの内容を処理するけど、
実際にthis.initは存在しない。
alert with Force Quit
無限ループや、極端に周期が短いset(Timeout or Interval)や、
予想よりも列挙が大量な場所で、
alert()を使ってしまった時に強制終了できるやつ。
要は、間違えちゃった時にキャンセルできるalert()
どこかで既に出ていると思うけど、
まあ、いいや。
Snipplralert with Force Quit
Posted by inamorix on January 9th, 2008
- window.alert = function (msg) {
- if (!confirm(msg)) throw new Error('Force Quit');
- };