it-swarm-ru.tech

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

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

163
Aditya Shukla

В конечном итоге он гарантирует, что значение 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.

373
user113716

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

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

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

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

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

Объект активации
Scope Chain
это значение

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

.call()
.apply()

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

foobar.call({test: 5});

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

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

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

49
jAndy

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

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

Та же цель может быть достигнута с помощью "Выражения немедленного вызова функции, кратко: 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>
1
Legends