2

HTML の A タグを操作する JavaScript コードを見ていますが、「onclick」プロパティの設定方法がわかりません。ytplayer_playitem をインデックス変数 j で更新してから ytplayer_playlazy(1000) を呼び出すように指示しているようです

しかし、すべての括弧はどうなっていますか? javascript 構文のどのような詳細により、このように設定できますか?

var a = document.createElement("a");
a.href = "#ytplayer";
a.onclick = (function (j) {
    return function () {
        ytplayer_playitem = j;
        ytplayer_playlazy(1000);
    };
})(i);
4

5 に答える 5

5

さて、基本的に、の値はonclick要素がクリックされたときに呼び出される関数です。ユーザーが要素をクリックしたときに何をしたいのかは、関数の本体に入ります。

名前付き関数を作成し、それを要素のonclick属性に割り当てることができます。

function youClickedMe() {
  ...
}
a.onclick = youClickedMe

しかし、それは他のどこでも参照されることのない関数名で名前空間を乱雑にします。必要な場所に匿名関数を作成する方がクリーンです。通常、これは次のようになります。

a.onclick = function() { ... }

しかし、あなたの特定の例でそれを試してみると:

a.onclick = function() { 
  ytplayer_playitem = something; // ??
  ytplayer_playlazy(1000); 
}

再生されるをハードコーディングしていることsomethingがわかります。元のコードは、再生するためのクリック可能なリンクをいくつか生成するループから取得されたと想定しています。上記のコードでは、これらのリンクはすべて同じように機能しますが、これはおそらくあなたが望むものではありません。

これまでのところ、とても簡単ですが、この次の飛躍はそれがトリッキーになるところです。解決策は明らかなようです。ループ内にいる場合は、関数本体内でループ変数を使用しないのはなぜですか。

// THIS DOESN'T WORK
a.onclick = function() { 
  ytplayer_playitem = i; 
  ytplayer_playlazy(1000); 
}

それは機能するはずですが、残念ながら、関数の内部は、関数が作成されたときではなく、関数が呼び出されiたときの変数の値を参照します。ユーザーがリンクをクリックするまでに、すべてのリンクを作成したループが実行され、ループの記述方法に応じて、最終的な値(おそらく、リストの最後のアイテムまたはそのアイテムのインデックスより1つ大きいアイテム)が作成されます。 。その値が何であれ、すべてのリンクが同じアイテムを再生するという状況が再び発生します。ii

コードのソリューションは、戻り値が別の関数である関数を使用することで、少しメタを取得します。ループ制御変数を引数として母関数に渡すと、それが作成する新しい関数はそのパラメーターを参照し、次の理由で外部引数変数の値に何が起こったとしても、常に最初に渡された値を取得できます。

function generate_onclick(j) {
    // no matter when the returned function is called, its "j" will be 
    // the value passed into this call of "generate_onclick"
    return function() { ytplayer_playitem = j; ytplayer_playlazy(1000); }
}

これを使用するには、次のようにループ内で呼び出します。

a.onclick = generate_onclick(i);

生成された各関数は、独自のj変数を取得します。この変数は、いつ変更されるかではなく、その値を永久に保持しますi。したがって、各リンクは正しい役割を果たします。任務完了!

これは、投稿された元のコードが行っていることとまったく同じですが、1つの小さな違いがあります。私の説明の最初のステップと同様に、作成者は名前付き関数を定義する代わりに無名関数を使用することを選択しました。ここでの他の違いは、定義した直後にその匿名関数も呼び出していることです。このコード:

a.onclick = (function (j) { ... })(i)

このコードの匿名バージョンは次のとおりです。

function gen(j) { ... }
a.onclick = gen(i)

JavaScriptのセミコロン挿入規則のため、匿名バージョンの周りに追加の括弧が必要です。function (y) {...}(blah)スタンドアロンの関数定義としてコンパイルされ、その後に関数呼び出しではなく、括弧で囲まれたスタンドアロンの式が続きます。

于 2012-05-23T18:30:01.177 に答える
3

「しかし、すべての括弧はどうしたのですか?」

括弧のほとんどは、あなたが期待することをしているだけです。

技術的には必要ない追加のセットがありますが、関数が呼び出されていることを示すヒントとしてよく使用されます。

                       // v-v---these are part of the function definition like normal
    a.onclick = (function (j) {
           //   ^-----------this and...v
        return function () {
            ytplayer_playitem = j;
            ytplayer_playlazy(1000);
        };
 //  v---...this are technically not needed here, but are used as a hint
    })(i);
 //   ^-^---these invoked the function like normal

「javascript構文のどのような詳細により、このように設定できますか?」

i結果として、関数はすぐに呼び出され、その値がjすぐに呼び出された関数のパラメーターによって参照されるように渡されます。

これにより、返された関数が引き続きアクセスできる変数スコープが作成されます。このようにして、ループで上書きされるj変数ではなく、常に変数にアクセスできます。i


これらのインライン化された関数は、IMO で少し悪用されています。単純に名前付き関数にすると、より明確になります。

for(var i = 0; i < 10; i++) {
    // create the new element
    a.onclick = createHandler(i);
    // append it somewhere
}

function createHandler (j) {
    return function () {
        ytplayer_playitem = j;
        ytplayer_playlazy(1000);
    };
}

結果のハンドラーはまったく同じですが、コードははるかにわかりにくくなっています。

于 2012-05-23T18:24:14.763 に答える
1
a.onclick = (function (j) {
    return function () {
        ytplayer_playitem = j;
        ytplayer_playlazy(1000);
    };
})(i);

これにより、「クロージャー」が作成iされ、ハンドラーにバインドされているその値がi「その時点」の値でありi、一般的ではないことが保証されます。

あなたのコードでは、内の関数()は式であり、実行されて変数を渡しましたi。これは(i)最後の部分に表示されます。この実行された関数式では、iがローカル変数になりますj。この実行された関数式は、「その時点で」onclickの値を持つイベントにバインドされるハンドラ関数を返します。ji


クロージャを使用しなかった場合:

//suppose i is 1
var i = 1;

a.onclick = function () {
    ytplayer_playitem = i;
    ytplayer_playlazy(1000);
};

//and changed i
i = 2;

//if you clicked the <a>, it would not be 1 onclick but 2 because you 
//did not assign the value of i "at that time". i is "tangible" this way
于 2012-05-23T18:23:44.723 に答える
1

そうですね、周囲のコードは次のようになると思います。

for (var i = 0; i < playitems.length; i++) {
    // above code here
}

さて、ここで明らかなことをして、次のonclickようにプロパティを割り当てることができます:

a.onclick = function() {
    ytplayer_playitem = i;
    ytplayer_playlazy(1000);
};

ただしi、値が変化するため、うまく機能しません。どちらのリンクがクリックさiれても、その時点での の値がリストの最後のリンクになるため、最後のリンクがアクティブ化されます。

したがって、これを防ぐ必要があります。これを行うには、新しいスコープを作成する必要があります。これは、すぐに呼び出される追加の関数を作成することによって行われます。

(function (j) {
    // some code here
})(i);

が関数に渡されているためi、保持されている変数への参照ではなく、値が渡されます。これは、正しい値への参照を持つ関数を定義できるようになったことを意味します。したがって、クリック処理関数を返す追加の関数を取得します。

a.onclick = (function (j) { // j is the right number and always will be
   return function () { // this function is the click handler
       ytplayer_playitem = j;
       ytplayer_playlazy(1000);
   };
})(i);

そのため、各a要素には独自のクリック ハンドラー関数があり、それぞれに独自のj変数 (正しい数値) があります。したがって、リンクをクリックすると、必要な機能が実行されます。

于 2012-05-23T18:27:49.430 に答える
0
a.onclick = (function (j) {
  return function () {
      ytplayer_playitem = j;
      ytplayer_playlazy(1000);
  };
})(i);

ここにあるのは、自己呼び出し型の無名関数です。それを分解してみましょう。最初に関数の本体をより単純なものに置き換えます(return j + 1;):

function( j ) { return j + 1; }

これは、ありふれた匿名関数またはクロージャです。このコード行は式であるため、値があり、その値は関数です。今、私たちはこれを行うことができます:

var foo = function( j ) { return j + 1; }

foo( 5 );  // => 6

ご存知のとおり、匿名関数を変数fooに割り当ててから、引数を指定して名前で関数を呼び出していますi。ただし、新しい変数を作成する代わりに、クロージャーは式であるため、代わりに次のように呼び出すことができます。

( function( j ) { return j + 1; } )( 5 );  // => 6

同じ結果。今、それはちょうど戻ってj + 1いますが、あなたのコードではそれは何か他のものを返します:別の無名関数:

return function() { /* ... */ }

関数を返す自己呼び出し無名関数があるとどうなりますか?結果は、返された「内部」関数です。

a.onclick = ( function( j ) {
    return function() {
             ytplayer_playitem = j;
             ytplayer_playlazy( 1000 );
           }
  }
)( i );

iが等しい場合は9a.onclickこれと同等の関数を保持します。

function() {
  ytplayer_playitem = 9;
  ytplayer_playlazy( 1000 );
}

他の人が指摘しているように、これの有用性は、呼び出されたときに、値の保持への参照を作成するのではなく、その時点の( function( j ) { /* ... */ } )( i )キャプチャして入れていることです。これは後で変更される可能性があります(おそらく変更される可能性があります)。i ji

于 2012-05-23T18:49:48.933 に答える