log.metatype

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 を書いちゃうんだよね〜
少し見直してみよう。

Consolas

テキストエディタのフォントにConsolasを使ってみた。
RegularではなくてItalicで。

OS XだからClearTypeとは見え方違うけど、
Italicにすると文学的で素敵になった(適当なイメージ)
“f” や “,” や “;” が特に素敵。いつものコードが違って見えるわぁ。

ConsolasはMicrosoft PowerPoint Viewer 2007にバンドルされている。

Class (instanceof Class)

簡易なクラス生成関数。
試してみたかった事は本格的なクラスの再現では無いので、
継承機能なんて無い。
だったら関数定義でいいじゃん。
って回りくどいのは、インスタンスからクラスを参照した時の挙動を変えたかったから。

SnipplrClass (instanceof Class)

Posted by inamorix on January 9th, 2008

  1. function Class (ns) {
  2.         this.toString = function () { return ns; };
  3. }
  4. Class.def = function (ns, ctx) {
  5.         var c  = window;
  6.         var ns = ns.split('.');
  7.         for (var i = 0, ix = ns.length - 1; i < ix; i++)
  8.                 c = c[ns[i]] instanceof Object ? c[ns[i]] : c[ns[i]] = {};
  9.        
  10.         if (!(ctx.init instanceof Function)) ctx.init = function () {};
  11.         c = c[ns[i]] = function () { this.constructor.apply(this, arguments); };
  12.         c.prototype             = new Class(ns.join('.'));
  13.         c.prototype.constructor = ctx.init;
  14.         for (var key in ctx) if (ctx.hasOwnProperty(key)) {
  15.                 if (key != 'init') c.prototype[key] = ctx[key];
  16.         }
  17.        
  18.         return c;
  19. };


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

  1. window.alert = function (msg) {
  2.         if (!confirm(msg)) throw new Error('Force Quit');
  3. };

Reflection of JavaScript

JavaScriptでリフレクションって、どんな感じだろう?
ひとまずnew演算子を直接指定しないで、インスタンスを取得する感じを
グローバルスコープ限定で適当に書いてみたけど、
使い道があんまり思いつかない。

Snipplrref

Posted by inamorix on December 4th, 2007

  1. String.prototype.ref = function () {
  2.         for (var args = [], i = 0; i < arguments.length; i++)
  3.                 args.push('arguments[' + i + ']');
  4.         if (window[this] && window[this] instanceof Function)
  5.                 return eval('(new window.' + this + '(' + args.join(',') + '))');
  6.         throw new Error('Function window.' + this + ' does not exist.');
  7. };


function test () {
	this.fn = function () { return 'hello'; };
}

こんな関数があったとして、

str = 'test';
str.ref().fn(); // 'hello'

文字列からインスタンスを生成、そのままメソッドコール。

str = 'Array';
str.ref(1, 2, 3).length; // 3

配列とかも出来るかな。
他は全然チェックしていない。