: O. Yuanying

JavaScriptメモ

概要

完美地図を作ってて気づいたJavaScriptの色々。

  • クラスが定義されているか調べる
  • IEでは配列の最後に「,」を置けない
  • window#onloadイベント時に複数の関数を実行
  • for文でも「 i 」は必ず宣言する
  • prototypeの罠

クラスが定義されているか調べる

あるクラスが定義されているか調べ、定義されていなかったら読み込む。

if(typeof Prototype == 'undefined') {
	document.write('<script type="text/javascript" src="prototype.js"></script>');
}

ちょっと使い方がめんどいけどなんとかなる。

IEでは配列の最後に「,」を置けない

JavaScriptの配列でもFirefoxとSafariでは配列の最後の要素にカンマをおける。これがなぜ良いかは「配列の要素を区切るカンマ、最後の要素の後に置いたら? 」を参照。

ただし、Internet Explorer 6ではエラー。

window#onloadイベント時に複数の関数を実行

window#onload時に動的に生成される複数の関数を実行する。

var initialize_functions = [];
var initializer = function() {
    for (var i=0; i<initialize_functions.length; i++) {
        initialize_functions[i]();
    }
};
Event.observe(window, "load", initializer);

まず、これが良いかどうか別として、グローバル変数にwindow#onload時実行される関数を保持する配列と、実際にwindow#onload時実行される関数を作る。

initializer関数はwindow#onload時に登録された関数をすべて実行する。

initialize_functions.push(
    function() {
        alert('Hello!!');
    }
);
initialize_functions.push(
    function() {
        alert('World!!');
    }
);

こんな感じで登録していく。

for文でも「 i 」は必ず宣言する

ある時、

for (i=0; i<2; i++) {
    other_function();
    alert(i);
}

と書いて実行してみたら、alertが3回されたあげく、最後に例外が発生した。

なんでかなーと思いつつデバッグしてみたら、other_function()内でもfor(i=0;i<2;i++)みたいなことやってて、変数 i がグローバルで定義されていたため i が毎回リセットされ、おかしなことになっていた模様。

これからはちゃんと面倒がらず、

for (var i=0; i<2; i++) {
    other_function();
    alert(i);
}

と書くことにする。

20071212追記

varはローカルスコープを持つ変数の宣言なので、上記の例だとforブロック内のスコープではなく、そのfor文が使われている関数内?のローカルスコープになってしまうらしい

というわけでvarの代わりにletを使うと良いようだ。

for (let i=0; i<2; i++) {
    other_function();
    alert(i);
}

prototypeの罠

var TestClass = Class.create();
TestClass.prototype = {
    pos: {x:0}
};

ってクラスを定義した後に、

var a = new TestClass();
a.pos.x = 500;

var b = new TestClass();
b.pos.x = 1000;

alert(a.pos.x);

で何が出力されるでしょう???

a.pos.xだから、500が出力されると思いきや、答え、「1000」。。。

どうも a.pos と b.pos が同じオブジェクトを指してるようだ。

var TestClass = Class.create();
TestClass.prototype = {
    pos: {x:0}
};

で、posを初期化したつもりでしたが、これはTestClass共通のプロトタイプを初期化してることになってしまうんですなー。

初期化するときはちゃんとコンストラクタ内でしましょう…。

var TestClass = Class.create();
TestClass.prototype = {
    pos: null,
    initialize: function () {
        pos = {x=0};
    }
};