1

推定

socketMethods:{
    update:function(data){
        this.emit("test", data);
        console.log("socket.update");
    },
    test:function(data){
        this.emit("test", data);
        console.log("socket.test");
    }
}

これは以下の可能性があり、「test」と「update」を発行することができ、「test」と「update」が呼び出されます

socket.on("test", function(data){
    dummy.socketMethods.test.call(socket, data);
});
socket.on("update", function(data){
    dummy.socketMethods.update.call(socket, data);
});

以下のこれらは不可能です...私が「test」または「update」を発行した場合、それぞれが代わりに「test」を呼び出します。FORループを使用すると、すべてのメソッドが呼び出される「最後の」メソッドになります。

つまり、socketMethodsオブジェクトで、テストが最初で、更新が2番目になるように、更新とテストを切り替えた場合です。「テスト」または「更新」のどちらを要求したかに関係なく、「更新」は常に呼び出されます

for(key in dummy.socketMethods){
    socket.on(key, function(data){
        dummy.socketMethods[key].call(socket, data);
    });
}



var methods = ["test", "update"];
while(methods.length !== 0){
    var method = methods.pop();
    console.log(method);
    socket.on(method, function(data){
        dummy.socketMethods[method].call(socket, data);
    });
}



var methods = ["test", "update"];
for(var i = 0; i < methods.length; i++){
    console.log(i);
    socket.on(methods[i], function(data){
        console.log(i);
        dummy.socketMethods[methods[i]].call(socket, data);
    });
}

CLUE:「i」を使用するforループには、2つのconsole.logがあります。2番目のconsole.logは「2」を返します

なぜこれが起こるのですか?そして、forループを使用してsocketMethodsをアタッチするにはどうすればよいですか?

4

1 に答える 1

5

クロージャーが作成時に外部関数の変数のを「トラップ」すると仮定するというよくある間違いを犯しています。そうではありません。外部関数の変数への参照を「トラップ」し、その値は、クロージャーが実行された時点で外部変数が持っているものになります。ループでクロージャーを作成している場合、その値はループの最後にあったものになります。

これを回避する方法は、外部変数の値を引数として使用する「囲み」クロージャを作成することです。これを行う 1 つの方法は、クロージャを生成するヘルパー関数を作成することです。最初の例では、次のことができます

function makeOn(key) {
  return function(data) {
    dummy.socketMethods[key].call(socket, data);
  }
}

for(key in dummy.socketMethods){
  socket.on(key, makeOn(key));
}

これで、各クロージャーでkey、適切な値に設定された (クロージャー間で異なる) 新しく作成された変数になります。

即時関数呼び出し (「自己実行関数」と呼ぶ人もいます) を使用して、同じことをもう少し簡潔に行うこともできますが、やや読みにくくなります。

于 2012-10-19T08:11:44.077 に答える