1

tl; drの場合、テーブル内の行のクリックハンドラーを作成するときに、クロージャーを使用すると、関数は、以下のコードのように毎回異なる場所ではなく、メモリ内の同じ場所を指すようになります。

そうでなければ:

私はjavascriptを学んでいて、クロージャとは何か、なぜそれが役立つのかを理解していると思います。これが私の推論です。それが正しいか?

HTMLテーブルの場合、次のコードは、最初または2番目の行をクリックした場合でも、常に最後の行がクリックされていることを示しています。私の推論は、コードが3つの異なるスタックフレームを作成し、iが0、1、2に等しい場合に1つずつ作成することです。2は最新のスタックフレームであるため、fnPtrの戻り値は2を指します。

var table = document.getElementById("tableid3");
var rows = table.getElementsByTagName("tr");
for (var i = 0; i < rows.length; i++) {
    var curRow = table.rows[i];
    //get cell data from first col of row
    var cell = curRow.getElementsByTagName("td")[0]; 
    var fnPtr = function() {
        alert("row " + i + " data="+ cell.innerHTML);
    }
curRow.onclick = fnPtr;
}

以下のコード(SOの質問から)はクロージャーを使用し、createfunc()のフレームである単一のスタックフレームのみを作成します。ただし、このフレーム内には、無名関数を指すローカル変数tmpがあります。createfunc()が0、1、および2で呼び出されると、戻り値は同じスタックフレーム(createfunc()のスタックフレーム内のスタックフレーム)を指します。これは、3つのスタックフレームが作成されないことを意味します。createfunc()が毎回戻る場合、戻り値スロットの値は、上記のコードのように毎回異なる場所ではなく、メモリ内の同じ場所を指します。

function createfunc(i) {
    var tmp = function() { console.log("My value: " + i); };
    console.log(tmp);
    return tmp;
}
for (var i = 0; i < 3; i++) {
    funcs[i] = createfunc(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

クロージャがどのように機能するか理解していますか?

4

2 に答える 2

1

これは、スタックではなく、スコープに関するものです。すべての関数定義はJavaScriptで新しいスコープを作成し、関数は常に祖先スコープにアクセスできます。

したがって、最初の例では、のすべてのインスタンスが親スコープからfnPtr同じものにアクセスできます。iいずれかの行がクリックされるまでに、forループはすでに終了しており、i3になります。

2番目の例では、返された各関数は、ファクトリ関数に渡されtmpた引数にアクセスできます。引数は、反復/呼び出しごとに異なります。i

于 2012-12-26T02:21:56.750 に答える
0

スタックフレームの観点からjavascriptがどのように機能するかを考えるのは良い考えではありません-javascriptはそれには高すぎるレベルです。

最初のコードスニペットでは、作成するfnPtr関数オブジェクトが実際の変数をキャプチャします(ただし、その値はまだ取得されていません)。したがって、後でその変数が変更された場合、関数が呼び出されると、i現在の時刻の変数値が使用されます。ループによって100個のfnPtr関数オブジェクトが作成された可能性がありますが、それらのすべてがまったく同じi変数への参照を保持しています。

2番目のスニペットは、プリミティブ値(数値など)を関数の引数として関数に渡すと、javascriptがそのコピーを作成するという事実を利用しています。したがって、createfuncを呼び出すたびに、変数の新しいコピーが作成され、この新しい変数の値は、createfuncが呼び出された時点で引数が持っていた値に設定されます。私が強調しているのは、これが新しい変数であり、他の関数がそれを参照していないという事実です。したがって、createfuncが新しい関数を返すと、その新しい関数は、コピーされた新しい排他的i変数への参照を保持します。

于 2012-12-26T02:19:21.620 に答える