addListener()やattachEvent()で引数



0   名前: めい : 2007/06/01(金) 20:00  ID:Maf/p1QT sub-ux
すみません、
addListener()やattachEvent()で
処理する関数の引数の渡し方について
なんですが、使い方に
addEventListener(イベント, 関数, キャプチャー)
となっていますが、この関数に
ついてはkansuu()じゃなくkansuu
書くとなっていて、これじゃ
関数に引数を渡せないなと思ったんです。
attachEvent()とも同じです。
ググッてもなかなか出てきません。
どなたかご存じでしたらおしえてください、
お願いします。

1   名前: めい : 2007/06/01(金) 20:00  ID:Maf/p1QT sub-ux
addListener()はaddEventListener()のまちがいです。

2   名前: NullPo : 2007/06/01(金) 20:00  ID:NwzmqAw7 sub-.G
・・・?

関数そのものを渡さないとイベント追加できないよね。
返り値を渡したいのであれば、
function kansuu() {
  return new Function();
}
にすればいいかな。

3   名前: めい : 2007/06/01(金) 20:00  ID:Maf/p1QT sub-ux
すみません。
普通関数を呼び出す時は
kansuu();やkansuu2(引数1, 引数2…);
となりますよね。
でもaddEventListener()の場合
関数の呼び出し(設定)が
kansuuやkansuu2と書かなくてはならず、
()を省略してしまうので、
kansuu2等に引数を渡すのは
どうしたらいいのかなと思ったんです。

4   名前: 匿名 : 2007/06/01(金) 20:00  ID:.6R45sYM sub-Cz
サンプルコードには何度も書いているはずなんだけどな。
node.addEventListener ('click', function (event) { kansuu (event, 1, 2); }, false);

ただし、イベントリスナを無名関数にすると後で removeEventListener できなくなるので、慎重を期すなら、
var listener = function (event) { kansuu (event, 1, 2); };
node.addEventListener ('click', listener, false);
...
node.removeEventListener ('click', listener, false);

のように関数への参照を保持しておいた方が良いかもしれない。



以下余談。

DOM-Events の仕様を見ると、イベントリスナは EventListener インタフェースを持つオブジェクトとある。ECMAScript 上では、普通の Function が EventListener オブジェクトとして扱われる。

だが、Firefox、Opera では、イベントリスナとして EventListener を模した Object を渡すことができる。
var listener = {
    handleEvent : function (event) { ; }, // イベントハンドラ
    ...   // 以下、自由にユーザ定義メソッド、プロパティを追加
};

node.addEventListener ('click', listener, false);

イベント発生時には、リスナの handleEvent メソッドに event オブジェクトが渡される。ここで重要なのは、handleEvent 実行時の this 値がリスナ登録ノードではなく、リスナオブジェクトであること。これで、イベント関連のデータをまとめておけるし、何より this 値を保存するのにクロージャを使って云々、といった作業から解放される。

多くの実装は後方互換性のため、ハンドラ内の this 値がリスナの登録ノードを指す。しかし、DOM-Events にそのような規定はないし、そもそもリスナの登録ノードは event.currentTarget で参照できるのだから、this まで同じものを指す必要はない。次バージョンの Safari でも、イベントリスナとして Object を渡せるようになる。
http://nanto.asablo.jp/blog/2007/03/23/1339502#domspecvsbrowser-EventListener-impl



IE では、attachEvent に渡したハンドラ内では this 値が null という、ちょっとありえない事態になる。
node.attachEvent ('onclick', functioin (e) { this; /*null*/ } );

そこで、以下のように考えてみた。
var handler = function (event) {
    return arguments.callee.listener.handleEvent (event);
};
handller.listener = {
    handleEvent : function (event) { ; },
    ...
};
node.attachEvent ('onclick', handler);

arguments.callee を使うので IE5.5 以上になるが、こうすれば、ハンドラ内の this 値が listener オブジェクトを指す。

要するに、関数のプロパティとして必要なデータを貼り付けておけば、関数内では arguments.callee を通してそのデータを参照できるので、引数にこだわる必要もないのでは、というお話。

5   名前: 匿名 : 2007/06/01(金) 20:00  ID:.6R45sYM sub-Cz
> 関数のプロパティとして必要なデータを貼り付けておけば

ああもちろん、そのプロパティは外部から参照・破壊しうるので、用途によりけりだけど。

6   名前: 匿名 : 2007/06/01(金) 20:00  ID:.6R45sYM sub-Cz
連投ごめん。

>>4
> IE では、attachEvent に渡したハンドラ内では this 値が null という、ちょっとありえない事態になる。

これ嘘だったかも。今確認したら window を返しやがった。昔実験した時は null だったんだがなあ。

まあ、IE だからしようがない。attachEvent() によるハンドラは、ノードのメソッドとしてではなく単なる関数として呼び出されることが分かれば十分なので、深く考えないことにする。

# 脱線し過ぎた。ごめん。

7   名前: めい : 2007/06/01(金) 20:00  ID:ov1YsV3c sub-ux
>>4>>5>>6さんありがとうございます。
昨日あれから掲示板を見られなくて
お返事できませんでした。
これから試してみます。

8   名前: めい : 2007/06/01(金) 20:00  ID:ov1YsV3c sub-ux
出来ました!
しかも複数、関数を入れられるんですね。
しかし、いまいち
function (event) { kansuu (event, 1, 2); }, 
の文法の意味が分かりません。
window.onload = function(){
    処理
}
とおなじようないみですか?
初歩的な関数の作り方しか知りませんので。

9   名前: 匿名 : 2007/06/01(金) 20:00  ID:3Dau8SBs sub-Cz
function listener (event) { ...; }

node.addEventListener (
    'onclick',
    listener,
    false
);

のように関数定義に名前を付けて識別するのではなく、
node.addEventListener (
    'onclick',
    function (event) { ...; },
    false
)

と、その場で関数を定義して、そのまま登録させただけ。window.onload も同じ。
function handler (event) { ...; }
window.onload = handler;
window.onload = function (event) { ...; };

後者はその場で関数を定義して、そのまま window.onload に代入しているだけ。

10   名前: めい : 2007/06/01(金) 20:00  ID:Maf/p1QT sub-ux
なるほど!
無名関数ってやつですね。
ありがとうございました。

11   名前: 匿名 : 2007/06/01(金) 20:00  ID:VdNduhWX sub-Cz
確かに無名関数なんだけど、名前を付けても構わないよ。
node.addEventListener (
    'onclick',
    function listener (event) { ...; },
    false
);
window.onload = function handler (event) { ...; };

名前を付けた場合、その名前は作成した関数内からのみ参照できる。無名関数であれ名前付き関数であれ、関数式でその場で関数を作成しているというのがポイント。

名前を付けておくと、再帰とかややこしいスコープになるときは便利。ただし、Safari は名前付きの関数式を扱えない(無名関数しか扱えない)ので注意。

一覧へ戻る