3

与えられた:

function shout(){ alert('Hello!'); }
var dasarray = [ shout ];

shout();
dasarray[0]();

shout = function(){ alert('World!'); }

shout();
dasarray[0]();

出力:

Hello!

Hello!

World!

Hello!

dasarray関数への参照を受け取ったと思っていたのですshoutが、残念ながら4番目の出力もhelloです。私が正しいと仮定すると、shout関数を正しく変更できましたが、これは、関数が参照によってに渡されなかったという私の仮定につながりますdasarray

配列の代わりに、私はすでにこの例をオブジェクトで試しました。

dasarray = { myfunction: shout }

同じ、残念な結果で。

私の意図は、順番に実行され、リアルタイムで拡張できる関数の配列/オブジェクト/関数を使用することです。

たとえば、JavaScriptコードを新しい機能で拡張し、正しい順序で実行される既存のイベントに関数呼び出しを追加します。

では、参照によって関数を配列/オブジェクトに配置するにはどうすればよいですか?


良い答えをありがとう。この設定につながるので、私はEliの答えを選んだことを説明したかっただけです。

zzz = {
    calls: [],
    shout: function(message) {
        alert('Shouting: ' + message);
    },
    initialize: function () {
        zzz.calls.push(['shout','Hello World']);
        zzz.calls.push(['shout','this is']);
        zzz.calls.push(['shout','my last shout!']);
        zzz.run();

        zzz.shout = function(){ alert('modified!'); };
        zzz.run();
    },
    run: function () {
        $.each(zzz.calls, function(){ zzz[this[0]](this[1]); }); // <- Using jQuery $.each here, just to keep it easy
    }
};

zzz.initialize();
4

2 に答える 2

7

dasarrayが関数への参照を受け取ることを期待していましたshout

します。変数への参照を受け取りませ。(関数宣言で関数の名前によって定義される記号は、事実上すべての目的と目的で変数です。これが、後で変数に割り当てることができる理由です。)したがって、後の行でその変数を変更します。 shout

shout = function(){ alert('World!'); }

...の以前の関数への参照には影響しませんdasarray

オブジェクト参照は、オブジェクトの場所を示す値と考えてください。あなたがするとき:

function shout(){ alert('Hello!'); }

...シンボルは、次のように、その関数がどこにあるかを示すshoutを受け取ります。

関数オブジェクトを指す可変シャウト

次に、あなたがするとき:

var dasarray = [ shout ];

...そのは配列の最初のエントリに入れられます。これで、シンボルshoutと両方の最初のエントリdasarrayの値が同じになり、JavaScriptエンジンにメモリ内のその関数オブジェクトの場所を指示します。だから私たちはこれを持っています:

同じ関数オブジェクトを指す変数shoutおよびdasarrayエントリー0

ただし、変数shoutとのエントリはdasarray、相互に何の関係もありません。

次に、これを行います。

shout = function(){ alert('World!'); }

...新しい関数を作成し、shoutその新しい関数がどこにあるかを示す新しい値を変数に格納します。dasarrayただし、これはのエントリに格納されている値には影響しません0。最終的には次のようになります。

2番目の関数を指すVarshout、最初の関数を指すdasarrayエントリ0

私は「値」をずっと上で言っています。なぜなら、それが「オブジェクト参照」であるからです。値と同じように、値5です。値が使用される方法は、オブジェクトがどこにあるかを調べることです。ある変数から別の変数にその値を割り当てると、ある変数から別の変数に値をコピーするときに値5がコピーされるのと同じように、値がコピーされます。

Eliの回避策があまり好きだとは言えません。むしろ、もっと直接的に、単純な方法でオブジェクトを使用したいと思います。

var obj = {
    shout: function() { alert("Hello!"); }
};
var dasarray = [ obj ];

obj.shout();                               // Hello!
dasarray[0].shout();                       // Hello!

obj.shout = function() { alert("World"); };

obj.shout();                               // World!
dasarray[0].shout();                       // World!
于 2013-03-15T17:29:10.023 に答える
3

TJの答えに同意します。ただし、ある種の回避策を実行したい場合は、関数のキャッシュから常に「ジャストインタイム」ルックアップを実行する関数を作成できます。このフィドルを見る

var getFunctionRef = function(funcName)
{
    return function() { global[funcName](); };
}

var global = { };
var arr = [];

global.shout = function() { alert('hello'); }

arr[0] = getFunctionRef('shout');

global.shout = function() { alert('world'); }

arr[0]();

これは非常に基本的な例です。それを行うにはもっと広範な方法があります。しかし、これは概念を実証する必要があります。

于 2013-03-15T17:34:09.723 に答える