Понимание $.proxy() в jQuery

Из документов я понимаю, что .proxy() изменил бы область действия функции, передаваемой в качестве аргумента. Может кто-нибудь объяснить мне это лучше? Почему мы должны это делать?

4 ответа

Решение

Что он в конечном итоге делает, так это гарантирует, что ценность this в функции будет значение, которое вы хотите.

Типичным примером является setTimeout что происходит внутри click обработчик.

Возьми это:

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

Намерение достаточно простое. когда myElement щелкнул, он должен получить класс aNewClass, Внутри обработчика this представляет элемент, который был нажат

Но что, если мы хотим небольшую задержку перед добавлением класса? Мы могли бы использовать setTimeout чтобы достичь этого, но проблема в том, что какую бы функцию мы ни давали setTimeout, значение this внутри этой функции будет 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 контекст.

Не вдаваясь в подробности (что было бы необходимо, поскольку речь идет о Context в ECMAScript, переменной this context и т. Д.)

В ECMA-/Javascript есть три разных типа "Контекстов":

  • Глобальный контекст
  • Контекст функции
  • Eval Context

Каждый код выполняется в контексте выполнения. Существует один глобальный контекст, и может быть много экземпляров функциональных (и eval) контекстов. Теперь интересная часть:

Каждый вызов функции входит в контекст выполнения функции. Контекст выполнения функции выглядит так:

Объект Активации
Цепочка прицела
это значение

Таким образом, это значение является специальным объектом, который связан с контекстом выполнения. В ECMA-/Javascript есть две функции, которые могут изменять значение this в контексте выполнения функции:

.call()
.apply()

Если у нас есть функция foobar() мы можем изменить это значение, вызвав:

foobar.call({test: 5});

Теперь мы можем получить доступ в foobar объект, который мы передали:

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

Это именно то, что jQuery.proxy() делает. Требуется function а также context (который является ничем иным, как объектом) и связывает функцию, вызывая .call() или же .apply() и возвращает эту новую функцию.

Я написал эту функцию:

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); }
}

Та же цель может быть достигнута с помощью самозапускающейся функции:

    $('#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>

Другие вопросы по тегам