より良い環境を求めて このページをアンテナに追加 RSSフィード

2007-06-17

[] IEが重い

firefoxだと重くないのに、IEだと激重。

getElementsByClassName()は重すぎだから、getElementsByTagName()で絞ってからhasClassName()で検索すると早くなった。


あとEvent.observe(element, 'mouseover', func) が重い。

軽くするためにはHTMLのタグに直接書かないとだめか・・?


javascriptが柔軟だからって、効率よく短く書けばいいってもんでもないんだな。

2007-03-12

[][] innerHTML

JavaScriptでだいぶハマってた。

単純な文字列置換でもミスるし・・。Ajaxで取ってきたテキストがIEだとタグ名が大文字になるのね。


あとinnerHTML。

prototype.jsを使うとHTMLElementが拡張されている。

タグには _extended="true" が追加されている。

そのinnerHTMLを取ってきてごにょごにょして表示したりするとエラーになることがある。

innerHTMLでは_extended="true"の文字列はコピーされるけど、ただのテキストなので実際にはprototype.jsによって拡張されたメソッドはコピーされていない。しかしこのテキストをElementに差し込んでprototype.jsの機能を使おうとすると、存在しない関数を呼び出してエラーになる。

innerHTMLじゃなくてDOMで操作すべきなんだな・・ちょっと面倒くさい。

2007-01-16

[] イベントハンドラの引数

bindAsEventListener()で追加の引数を受け取れないと悩んでいた。最新のリビジョンを見たら理解した。*1


最新バージョンではcall()を使わずにどちらもapply()でやっていた。

で、やっぱりbind()ソースの

args.concat($A(arguments))

の部分が理解できない。args = $A(arguments)とやっているのに、二重にしているような・・と思ったら唐突に理解できた。

カリー化みたいなもんか。

func = bind(obj, arg1, arg2);

とやっておいて

func(arg3, arg4);

とするのか。


でも今使ってるバージョン1.4のbindAsEventListener()は引数を複数取れない。

どうしよう。

実質的な動作としてはbind()もbindAsEventListener()も同じなんだけど、上に書いたように引数の順番が決められる。

最新リビジョンのbindAsEventListener()は、イベントハンドラ関数の引数が

function callback(event, arg1, arg2, ...){...}

のようになるのに対して、bindで行うと

function callback(arg1, arg2, ..., event){...}

になる。なるほど、分かりやすさの点ではbindAsEventListener()関数は意味があるのか。

まぁ・・今のところはbind()でいいか。

*1:昨日の「bind()のソースは$A(arguments)とかやっていてbindAsEventListener()の方はやってないのだが、この違いはまだ理解できていない。」の部分

2007-01-15 初心者によるJavaScript漬けの日々

[][] prototype.jsで綺麗なコードを書く

hawkさんにかなり助けてもらいつつ、コードが綺麗になってきたのでまとめてみる。

Ajaxイン・アクションの復習も兼ねて。


理解できてくると段々楽しくなってくるね。ブラウザの挙動の違いは困るけどprototype.jsが結構吸収してくれてるぽい。



HTMLからJavaScriptのコードを取り除く

知っている人は何を今更と思うかもしれないが、他の言語をやっていてJavaScriptに手を出そうとしたときに気付きにくい。入門書ではほとんどHTMLのタグの中に書いてるんだもの。

Event.observe(window, 'load', function(){
    // 初期化処理
    Initializer.initLink();
    Initializer.initForm();
});

ネットでもbodyタグにonload=hoge() としている例が沢山あるがそれは好ましくない。JavaScriptを外部ファイルにしきれていないのでちゃんと分ける。


オブジェクト指向で書く

上の例だと

var Initializer = {
    initLink: function(){
    },
    initForm: function(){
    }
}

のようなオブジェクトを定義しておいて名前空間を分ける。

または、

function Initializer(){
    this.initLink();
    this.initForm();
}
Initializer.prototype.initLink = function(){
}
Initializer.prototype.initForm = function(){
}

Event.observe(window, 'load', function(){
    var initializer = new Initializer();
});

でも良い。こちらはオブジェクトを複数扱ったり状態を保持したいとき向け。

イベントハンドラはリスナに登録する

汎用的にするには、onclick等に直接書かずにイベントリスナにハンドラ関数を登録する。

var Initializer = {
    initLink: function(){
        Event.observe('ajaxtext', 'click', function(){
            // Ajaxでリンク先を表示したりとか
        });
    },
    initForm: function(){
        Event.observe('form', 'submit', (function(e){
            if (this.checkFormError()){
                // 入力のエラーなど
                $('errorMessage').innerHTML = 'error!';
                Event.stop(e);
            }
        }).bind(this));
    },
    initInfo: function(menuItem){
        Event.observe(menuItem, 'click', this.viewInformation.bind($(menuItem)));
    },
    checkFormError: function(){...},
    viewInformation: function(){...}
}

イベントを登録するにはbindAsEventListener()の方が適しているようだが

http://blog.hawklab.jp/item-62.html

Event.observe()を使うならば必要ないっぽい。実際 bindAsEventListener()内で event||window.event としているだけだった。

$('form').onclick = this.myFunc.bindAsEventListener(this, arg1, arg2);

とobserveを使わない場合には有効だが、こっちを使う必要はなさそう。bind()のソースは$A(arguments)とかやっていてbindAsEventListener()の方はやってないのだが、この違いはまだ理解できていない。

# 追記

# なんか複数の引数(arg1, arg2)を受け取れなかった・・イベントだから引数はeventのみ?


イベントリスナは複数登録できる。onclickに対する動作を一カ所にまとめて書かなくてもいいようになる。

実行される順番は・・・不定だったような。実行される順番はIEのattachEventとaddEventListenerで逆(?)なので、複数登録する場合は互いに独立した関数にする。



[][] prototype.jsのbind

hawkさんにコメントをいただいたのでコードの見直し。

どの部分で問題になってたのか忘れてしまったorz


でも数カ所で

obj.func1 = function(element){
  var obj = this;

  Event.observe(element, 'onclick', function(e){ obj.func2(); });
}
obj.func2 = function(){...}

とやってる。

これはbindを使うべき・・なのかな。


bindって使ったことなかったけど

Event.observe(element, ’event’, (function(){...}).bind(element))

function(){...}のthisがelementに固定されるわけか・・。これをelementじゃなくて呼び出しているオブジェクト自身にしようと思えばthisと書くだけでいいのかな?スコープの範囲が変わってるわけではないからthisでいいんだろう(たぶん

bindAsEventListener()も使っていった方がすっきりしそうだけど、もうちょっと理解が追いついてからにしよう・・。



[][] デフォルト動作のキャンセル

onsubmitなどでreturn false;を返すと、デフォルトの動作をキャンセルできる。

で、これもEvent.observe()では無効なのか。

同じイベントに何個でもハンドラを登録できることを考えると普通の動きなのかな。