3

ループを作っていたらいきなり質問が来ました。これは「正しい方法」であるはずです:

    // code.. 
    $('tr','#my_table').each(function(){
        $(this).click(function(){
            var show_id = $(this).attr('data-show-id');
            // code..
            // code..
        });
    });
    // code.. 

また

    // code.. 
    var show_id = 0; /* HERE */ 
    $('tr','#my_table').each(function(){
        $(this).click(function(){
            show_id = $(this).attr('data-show-id');
            // code..
            // code..
        });
    });

最初の例では、それぞれtrに新しい variableを作成しますshow_idshow_id2 番目の例では、テーブル内のすべての に同じグローバルを使用し、tr各 tr に再設定します。

したがって、問題は次のとおりです。プログラミング言語に関係なく-関数が終了するときに解放される新しい変数をループごとに作成するか、実行全体のメモリを「キャッチ」して毎回変数を再作成するのを避ける方が良い方法ですか?

4

5 に答える 5

10

変数はループ中に作成されません。これは、単独で実行されるイベント ハンドラーでのみ必要です。変数を外部に移動する (内部でのみ必要な場合) には、次の 3 つの問題があります。

  • より高いスコープの変数へのアクセスは少し遅くなります
  • ガベージ コレクションは値を収集しません (メモリ効率が悪い)
  • イベント ハンドラーの非同期動作が変数にアクセスするが、ハンドラーが複数回呼び出される場合に発生する可能性のある問題

2番目のポイントもあなたの質問への答えです:

関数が終了したときに解放される新しい変数をループごとに作成するか、実行全体のメモリを「キャッチ」して、毎回変数を再作成しないようにすることをお勧めしますか?

ずっとメモリを浪費するのはほとんど意味がありません。関数スコープの作成は高速です。宣言を変数の使用から遠ざけることは悪い習慣と見なされる可能性があり、別のスコープに移動するとエラーが発生する可能性さえあります。

大きなメモリを搭載したマシンで実行する場合、メモリの事前割り当ては理にかなっています。オブジェクトの作成/削除 (すべてのハンドラーで一定のまま) は低速で​​す。

于 2013-07-30T12:38:28.097 に答える
1

それは、実際には、その変数がどこに存在する必要があるかによって異なります。JS は、変数を現在のスコープ (宣言されているスコープ) の先頭に持ち上げるか、var が宣言されていない場合は (悪) グローバルを作成します。

ループ内で var を宣言しても問題ありません。

for (var i=0;i<10;i++)
{
    var j = 1*2;
}

に翻訳されます:

var i, j;
for (i=0;i<10;i++)
{
    j = 1*2;
}

ただし、いくつかの「経験則」があります。

  • グローバル変数を使用している場合は、おそらく間違いを犯しています
  • ループ内で変数を宣言している場合、おそらくその変数は必要ありません
  • 変数を宣言していない場合は、スクリプトで次のことを試してください。

(function()
{
    'use strict';
    //your code here
}());

そして、暗黙のグローバルフリーになるまでデバッグしてください。

あなたの例でshow_idは、グローバルスコープ($(document).ready(callbackとにかくスコープ)で宣言するか、clickハンドラー内で宣言するかの選択を「提供」しています。コールバックで変数を宣言することを妨げるものは何もありませeachん。この場合、大きな違いはありませんが、それは別の問題です。

JS では、すべての関数に独自のスコープがあり、必要なスコープで変数を宣言します。

そうは言っても、パフォーマンスタグに気づいただけで、コードは効率の点で最悪です。行をループして、イベント ハンドラーを全体にバインドする代わりに、イベントをデリゲートします。

$('#my_table').on('click','tr',function(e)
{
    var show_id = e.target.attr('data-show-id');
});

このコードでshow_idは、クリック ハンドラーが返された後に GCshow_idされます。たとえば、次の行がクリックされたときを確認するために保持する必要がある場合です。

$('#my_table').on('click','tr',(function (show_id)
{
    return function(e)
    {
        console.log('show_id was: ' + show_id);
        show_id = e.target.attr('data-show-id');
        console.log('and is now: ' + show_id);
    };
}()));
console.log(show_id);//undefined

変数はスコープ内に保持されます ( でラップされた関数return functionは、show_id宣言されたとおりのスコープですが、その戻り値はその変数を参照するため、GC されません。その返された関数の外側では、より高いスコープにいるため、変数にまったくアクセスできません。できることは、その値を公開することです。

var someVar = {};
$('#my_table').on('click','tr',(function (show_id)
{
    return function(e)
    {
        show_id = e.target.attr('data-show-id');
        someVar.myTableClicks = show_id;
        console.log(someVar.myTableClicks);//value of show_id
    };
}()));
console.log(someVar.myTableClicks);//undefined
//after a couple of clicks
console.log(someVar.myTableClicks);//some value

show_idこれで、アクセスできる場所ならどこでもの値にアクセスできますsomeVar

個人的には、いくつかの変数を使用できるようにする必要があるグループ コードを保持することを好みます。

var access = (function(timer)
{
    var speed = 100,
    begin = function(callback, interval)
    {
        speed = +(interval) || speed;
        timer = setInterval(callback, speed);
    },
    stop = function()
    {
        clearInterval(timer);
    };
    return {start: start, stop: stop};
}());

この例では、startstop関数の両方が var にアクセスする必要がありますが、timer外部からのコードが の値を台無しにしたくないtimerので、これらの関数のみを公開しています。私の知る限り、コールバック引数関数にはtimerまたはspeed参照を含めることができますが、コールバック関数は定義により別のスコープで宣言されるため、シールドしようとしているspeedおよび変数を参照しません。したがって、アクセスできませんこのスコープ。それでも、絶対に確実にしたい場合は、いつでもこれを行うことができます:timer

var access = (function(timer)
{
    var speed = 100,
    begin = function(callback, interval)
    {
        speed = +(interval) || speed;
        timer = (function(timer, speed)
        {//masks timer & speed from the higher scope
            return setInterval(callback, speed);
        }('abc', 'def'));//assign dummy values
        timer = setInterval(callback, speed);
    },
    stop = function()
    {
        clearInterval(timer);
    };
    return {start: start, stop: stop};
}());
于 2013-07-30T12:37:31.813 に答える
0

すべての変数のメモリはメソッドの入り口で割り当てられるため、2 つの例は同等です。2 番目の例は、変数のスコープが制限されているため、より安全になるため、より優れています (ループ外で誤って変数を使用することはありません)。

于 2013-07-30T12:44:09.387 に答える
0

個人的に私は使用します:

    $("tr","#my_table").each(function(){
        $(this).on("click", function(){
             var $this = $(this);                
             var show_id = $this.data("show-id");
            // code..
            // code..
        });
    });
  1. on("click", function() {...}); を使用します。.click() の代わりに
  2. var $this = $(this) は、コードのさらに下で使用する場合に推奨されます。それ以外の場合は無視できます
  3. この場合の show_id は、このスコープ外ではアクセスできません。
  4. data-* 属性にアクセスするには、attr("- ") の代わりに data("- ") を使用する必要があります
于 2013-07-30T12:42:21.223 に答える
0

要件によって異なります。

最初の例:

$('tr','#my_table').each(function(){
        $(this).click(function(){
            var show_id = $(this).attr('data-show-id');
            // code..
        });
    });

変数はローカルであり、.each またはクリックでバインドされた無名関数内で使用できます。

2 番目の例:

var show_id = 0; /* HERE */ 
    $('tr','#my_table').each(function(){
        $(this).click(function(){
            show_id = $(this).attr('data-show-id');
            // code..
            // code..
        });
    });

ここで、変数はグローバルであるため、そのスコープはスクリプト全体で有効です!!!

于 2013-07-30T12:40:35.040 に答える