jQueryの$ .proxy()を理解する


167

ドキュメントから私はそれ.proxy()が引数として渡される関数のスコープを変更することを理解しています。誰かがこれをもっとよく説明してくれませんか?なぜこれを行う必要があるのですか?


1
ドキュメントによると、「このメソッドは、コンテキストが別のオブジェクトを指している要素にイベントハンドラーをアタッチするのに最も役立ちます。さらに、jQueryは、jQuery.proxy()から返された関数をバインドした場合でも、オリジナルを渡した場合でも、正しい関数をアンバインドします。」あなたが欠けていると思うその言い回しについて何か特別なことはありますか?
bzlm

1
?オリジナルの「.Whatの元の意味渡された場合、これは、また、jQueryのは、それが正しい関数まだバインド解除意志)あなたが結合していても機能はjQuery.proxy(から返されたことを確認しますここでは不明である
アーディティヤシュクラ

オリジナルは、プロキシが作成されたものです。しかし、あなたはこのことを完全に理解していないので、それを使用する必要があると確信していますか?
bzlm

1
これは$ .proxyがどのように機能するかを示すnettutsによる素晴らしいビデオチュートリアルです。http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-learning-jquery-1-4s-proxy/
フセイン

1
@bzlm、私がこの方法を思いついたとき、jqueryのドキュメントを読んでいました。
アディティアシュクラ

回答:


381

それが最終的に行うことはthis、関数内のの値がユーザーが望む値になることを保証することです。

一般的な例はsetTimeoutclickハンドラー内で発生するです。

これを取る:

$('#myElement').click(function() {
        // In this function, "this" is our DOM element.
    $(this).addClass('aNewClass');
});

その意図は十分単純です。myElementをクリックすると、クラスが取得されますaNewClass。ハンドラーの内側は、thisクリックされた要素を表します。

しかし、クラスを追加する前に短い遅延が必要な場合はどうでしょうか。私たちはsetTimeoutそれを達成するためにa を使用するかもしれませんが、問題は私たちに与える関数が何であれsetTimeoutthisその関数の内部の値がwindow要素の代わりになることです。

$('#myElement').click(function() {
    setTimeout(function() {
          // Problem! In this function "this" is not our element!
        $(this).addClass('aNewClass');
    }, 1000);
});

そのため、代わりに、を呼び出して$.proxy()、割り当てたい関数と値を送信し、その値をthis保持する関数を返すことができます。

$('#myElement').click(function() {
   // ------------------v--------give $.proxy our function,
    setTimeout($.proxy(function() {
        $(this).addClass('aNewClass');  // Now "this" is again our element
    }, this), 1000);
   // ---^--------------and tell it that we want our DOM element to be the
   //                      value of "this" in the function
});

したがって$.proxy()、関数と必要な値を指定thisした後、this適切に設定されることを保証する関数を返しました。

どうやってやるの?メソッドを使用して関数を呼び出す無名関数を返すだけで.apply()、の値を明示的に設定できますthis

返される関数を単純化すると、次のようになります。

function() {
    // v--------func is the function we gave to $.proxy
    func.apply( ctx );
    // ----------^------ ctx is the value we wanted for "this" (our DOM element)
}

したがって、この無名関数はに与えられsetTimeout、元の関数を適切なthisコンテキストで実行するだけです。


$.proxy(function () {...}, this)ではなく使用することの価値は何(function() {...}).call(this)ですか?違いはありますか?
ジャスティンモーガン

11
@JustinMorgan:.callあなたはすぐに関数を呼び出しています。では$.proxyFunction.prototype.bind新しい関数を返すようなものです。その新しい関数にはthis値が永続的にバインドされているため、それがに渡されて後で関数setTimeoutsetTimeout呼び出しても、正しいthis値が保持されます。
灰色の状態が

2
この手法の利点は、あるとしても、このようなものよりも優れていますか?$( '#myElement')。click(function(){var el = $(this); setTimeout(function(){el.addClass( 'aNewClass');}、1000);});
グレッグ

1
この例では$ .proxyメソッドを使用する必要はありません。代わりに、次のように簡単に書き直すことができます$( '#myElement')。click(function(){var that = this; setTimeout(function(){/ /ハンドラーメソッドのスコープで宣言された変数による新しいコンテキスト$(that).addClass( 'aNewClass');}、1000);});
ポール2013年

4
112kの担当者、恐ろしいJavaScript / jQueryの知識を持つ匿名ユーザーで、2011年10月以来見られていません... John Resigですか?
cantera 2013

49

詳細については説明しません(これはECMAScriptのコンテキストthisコンテキスト変数などのために必要です)。

ECMA- / Javascriptには、3つの異なるタイプの「コンテキスト」があります。

  • グローバルコンテキスト
  • 関数のコンテキスト
  • 評価コンテキスト

すべてのコードは、その実行コンテキストで実行されます。グローバルコンテキストが1つあり、関数(および評価)コンテキストのインスタンスが多数存在する可能性があります。今興味深い部分:

関数を呼び出すたびに、関数実行コンテキストに入ります。関数の実行コンテキストは次のようになります。

Activation Value
Scope Chain
this value

したがって、この値は実行コンテキストに関連する特別なオブジェクトです。ECMA- / Javascriptには、関数実行コンテキストでthis値を変更する可能性のある2つの関数があります。

.call()
.apply()

関数がある場合は、次の呼び出しでこの値をfoobar()変更できます。

foobar.call({test: 5});

これでfoobar、渡したオブジェクトにアクセスできます。

function foobar() { 
    this.test // === 5
}

これがまさに何をするかjQuery.proxy()です。functionand context(これはオブジェクトにすぎません)を受け取り、.call()or .apply()を呼び出して関数をリンクし、その新しい関数を返します。


1
優れた説明、関数の公式jQueryドキュメントよりもシンプル/優れています
higuaro

4

私はこの関数を書きました:

function my_proxy (func,obj)
{
    if (typeof(func)!="function")
        return;

    // If obj is empty or another set another object 
    if (!obj) obj=this;

    return function () { return func.apply(obj,arguments); }
}

1

同じ目的は、「即時に呼び出される関数式、短い:IIFE」自己実行関数を使用して達成できます 。

    $('#myElement').click(function() {  
      (function(el){
         setTimeout(function() {
              // Problem! In this function "this" is not our element!
            el.addClass('colorme');
        }, 1000);
      })($(this)); // self executing function   
    });
.colorme{
  color:red;
  font-size:20px;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>

  <div id="myElement">Click me</div>
</body>
</html>


2
これは通常、参照、「すぐに、呼び出される関数の式」(生命維持)ではなく、「自己実行中の関数」と呼ばれていますen.wikipedia.org/wiki/Immediately-invoked_function_expressionを
Chris Seed 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.