Comprensión $.() en jQuery


De docs entiendo que .proxy() cambiaría el alcance de la función pasada como argumento. ¿Podría alguien explicarme esto mejor? ¿Por qué deberíamos hacer esto?

Author: Xufox, 2011-02-13

4 answers

Lo que hace en última instancia es asegurar que el valor de this en una función será el valor que desea.

Un ejemplo común es en un setTimeout que tiene lugar dentro de un controlador click.

Toma esto:

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

La intención es bastante simple. Cuando se hace clic en myElement, debería obtener la clase aNewClass. Dentro del controlador this representa el elemento en el que se hizo clic.

Pero, ¿y si quisiéramos un breve retraso antes de añadir la clase? Podríamos usar un setTimeout para lograrla, pero el problema es que cualquiera que sea la función que le demos a setTimeout, el valor de this dentro de esa función será window en lugar de nuestro elemento.

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

Así que lo que podemos hacer en su lugar, es llamar a $.proxy(), enviándole la función y el valor que queremos asignar a this, y devolverá una función que conservará ese valor.

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

Así que después de dar $.proxy() la función, y el valor que queremos para this, devolvió una función que asegurará que this esté correctamente establecer.

¿Cómo lo hace? Simplemente devuelve una función anónima que llama a nuestra función usando el método .apply(), que le permite establecer explícitamente el valor de this.

Una mirada simplificada a la función que se devuelve puede verse como:

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

Así que esta función anónima se le da a setTimeout, y todo lo que hace es ejecutar nuestra función original con el contexto this apropiado.

 365
Author: user113716,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-13 20:07:30

Sin entrar en mayor detalle (lo cual sería necesario porque se trata de Context en ECMAScript, la esta variable de contexto etc.)

Hay tres tipos diferentes de "Contextos" en ECMA - / Javascript:

  • El contexto global
  • Contexto de la función
  • contexto de evaluación

Cada código se ejecuta en su contexto de ejecución . Hay un contexto global y puede haber muchos casos de contextos de función (y de evaluación). Ahora la parte interesante:

Cada llamada de una función entra en el contexto de ejecución de la función. Un contexto de ejecución de una función se parece a:

El Objeto de Activación
el Alcance de la Cadena de
este valor

Así que el este valor es un objeto especial que está relacionado con el contexto de ejecución. Hay dos funciones en ECMA - / Javascript que pueden cambiar el este valor en una función contexto de ejecución:

.call()
.apply()

Si tenemos una función foobar() podemos cambiar el este valor llamando:

foobar.call({test: 5});

Ahora podríamos acceder en foobar al objeto que pasamos:

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

Esto es exactamente lo que hace jQuery.proxy(). Toma function y context (que no es otra cosa que un objeto) y vincula la función invocando .call() o .apply() y devuelve esa nueva función.

 48
Author: jAndy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-03 01:20:45

He escrito esta función:

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
Author: sgv_test,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-05 17:15:24

El mismo objetivo se puede lograr usando una función autoejecutable:

    $('#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>
 0
Author: Legends,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-06 00:32:43