javascript this bind

javascript - Cuando pasas ''esto'' como argumento



this bind (4)

¿Está diseñado para establecerse donde se representa por primera vez en el código?

No. Se establece por cómo se llama a una función o por usar bind .

Por ejemplo, en mi ejemplo lo estoy usando con éxito para referirme a obj

Porque la función se llama usando:

obj.prepareRandomFunction();

que establece esto en la función a obj .

y también vinculando la función a obj

en:

var obj = { ... prepareRandomFunction: function() { randomFunction(this.sumData.bind(this)); } };

dado que prepareRandomFunction se ha llamado con obj como esto , entonces el valor de esto dentro de obj.sumData se establece en obj , y la llamada a randomFunction resuelve efectivamente:

randomFunction(obj.sumData.bind(obj));

pero dado que esto se pasa como una función de devolución de llamada, lo que impide que se configure como función aleatoria

El hecho de que haya configurado esto en obj en la llamada. Si desea que esto sea ​​una función aleatoria , deberá configurarlo. randomFunction no tiene un valor intrínseco para esto , se establece por cómo se llama la función (o el uso de bind ).

(es decir, ¿qué le impide pasar literalmente "this.sumData.bind (this)" para que esté configurado en randomFunction)?

Porque esto no es una función aleatoria cuando se ejecuta ese código.

Entonces:

obj.prepareRandomFunction();

llama a prepareRandomFunction con este conjunto a obj , que luego lo hace (reemplazando esto con obj :

randomFunction(obj.sumData.bind(obj));

Dentro de randomFunction , esto no se ha configurado, por lo que su valor predeterminado es el objeto global (irrelevante, ya que no se usa aquí). Entonces:

var randomFunction = function(callback) { var data = 10; callback(data); };

Que crea una variable local de datos con un valor de 10, luego llama a sumData con su conjunto a obj y pasa el valor de los datos . Entonces:

sumData: function(data) { var sum = this.initialData + data; console.log(sum); },

y como esto es obj , la asignación efectivamente resuelve:

var sum = obj.initialData + 10;

que es 30.

Estoy tratando de aprender sobre this , y me está confundiendo un poco aquí:

var randomFunction = function(callback) { var data = 10; callback(data); }; var obj = { initialData: 20, sumData: function(data) { var sum = this.initialData + data; console.log(sum); }, prepareRandomFunction: function() { randomFunction(this.sumData.bind(this)); } }; obj.prepareRandomFunction();

¿Está diseñado para establecerse donde se representa por primera vez en el código? Por ejemplo, en mi ejemplo, lo estoy usando con éxito para referirme a obj y también vincular la función a obj , pero dado que this se pasa como una función de devolución de llamada, lo que impide que se configure como función randomFunction (es decir, lo que lo detiene literalmente pasando "this.sumData.bind (this)" para que se establezca en randomFunction cuando se llama desde allí)?

Soy un novato tratando de aprender. Gracias.

Actualizado No estoy preguntando exactamente cómo funciona esto en general (no creo). Tengo curiosidad principalmente por saber por qué this se establece donde lo defino como el argumento de mi llamada randomFunction , y no dónde se llama a la callback llamada dentro de randomFunction . Podría estar equivocado, pero si tuviera que cambiar this.sumData.bind(this) con la callback(data) que tengo actualmente, creo que obtendría un resultado diferente. ¿Es porque la callback es una referencia a this.sumData.bind(this) cuando se definió por primera vez (y donde this es obj )?

Creo que he aprendido a través de este escenario que this se establece cuando se ejecuta. No se pasa como un argumento que se establecerá más adelante cuando se llame al argumento más adelante.


Esta es una autorreferencia de un objeto. Cuando crea un objeto, ya sea utilizando el nuevo operador, declarándolo como un objeto, literal o
Al llamar a uno de los integrantes de JS, esto se le asignará.
Pero como el alcance de JS es dinámico y más bien no transitorio, generalmente no puede confiar demasiado en este objeto. Es por eso que a menudo ves construcciones como oThis: this o var o


Paso a paso.

1) this dentro de prepareRandomFunction es obj

obj.prepareRandomFunction()

2) randomFunction toma una función:

randomFunction(this.sumData);

3) esa función se llama:

callback(data);

El aviso de callback se llama sin un punto, lo que significa que no tiene ningún valor para this , lo que significa que this es el objeto global (o undefined en modo estricto).

4) se llama a sumData :

var sum = this.initialData + data;

this es el objeto global, initialData no existe, agrega undefined a los data . Resultados inesperados

Solución: vincular this permanentemente:

randomFunction(this.sumData.bind(this));

4) se ejecuta sumData , this es obj , obj.initialData es 20 . Funciona.


this dentro de una llamada de función se establece de acuerdo a cómo se llama una función. Hay seis formas principales de configurar esto.

  1. Llamada de función normal: en una llamada de función normal como foo() , se establece en el objeto global (que es una window en un navegador) o en undefined (en el modo estricto de Javascript).

  2. Llamada de método: si se llama a un método como obj.foo() , entonces se establece en obj dentro de la función.

  3. .apply () o .call (): si se .apply() o .call() , this se establece de acuerdo con lo que se pasa a .apply() o .call() . Por ejemplo, podría hacer foo.call(myObj) y hacer que this se establezca en myObj dentro de foo() para esa llamada de función en particular.

  4. Uso de new: si llama a una función con new como new foo() , se crea un nuevo objeto y se llama a la función constructora foo con this conjunto al objeto recién creado.

  5. Uso de .bind (): al usar .bind() , se devuelve una nueva función de código auxiliar de esa llamada que usa internamente .apply() para establecer this puntero como se pasó a .bind() . FYI, este no es realmente un caso diferente porque .bind() se puede implementar con .apply() .

  6. Uso de la función de flecha de grasa ES6 La definición de una función a través de la sintaxis de flecha en ES6 + vinculará el valor léxico actual de this . Entonces, no importa cómo se llame a la función en otro lugar, el intérprete establecerá this valor en el valor que tiene cuando se definió la función. Esto es completamente diferente a todas las demás llamadas a funciones.

Existe una especie de séptimo método, a través de una función de devolución de llamada , pero en realidad no es su propio esquema, sino que la función que llama a la devolución de llamada utiliza uno de los esquemas anteriores y eso determina cuál será el valor de this cuando se llame a la devolución de llamada . Debe consultar la documentación o el código para la función de llamada o probarlo usted mismo para determinar a qué se configurará esto en una devolución de llamada.

Lo que es importante entender en Javascript es que cada llamada a una función o método en Javascript establece un nuevo valor para this . Y, qué valor se establece está determinado por cómo se llama la función.

Entonces, si pasa un método como una devolución de llamada simple, ese método, por defecto, no se llamará como obj.method() y, por lo tanto, no tendrá el valor correcto de this conjunto. Puede usar .bind() para .bind() ese problema.

También es útil saber que algunas funciones de devolución de llamada (como los controladores de eventos DOM) se invocan con un valor específico de this según lo establecido por la infraestructura que llama a la función de devolución de llamada. Internamente, todos usan .call() o .apply() por lo que esta no es una regla nueva, pero es algo a tener en cuenta. El "contrato" para una función de devolución de llamada puede incluir cómo establece el valor de this . Si no establece explícitamente el valor de this , se establecerá de acuerdo con la regla n. ° 1.

En ES6, llamar a una función mediante una función de flecha, mantiene el valor léxico actual de this . Aquí hay un ejemplo de la función de matriz que mantiene el léxico this de MDN :

function Person(){ this.age = 0; setInterval(() => { this.age++; // |this| properly refers to the person object }, 1000); } var p = new Person();

Su ejemplo de obj.prepareRandomFunction(); es la regla n. ° 2 anterior, por this que se establecerá en obj .

Su ejemplo de randomFunction(this.sumData.bind(this)) es la regla n. ° 1 anterior, por lo que this dentro de randomFunction se establecerá en el objeto global o undefined (si está en modo estricto).

Dado que randomFunction está llamando a una función de devolución de llamada que usó .bind() , el valor de this dentro de la función de devolución de llamada cuando se llama se establecerá en el valor de this que se pasó a .bind() en this.sumData.bind(this) según la regla # 5 anterior. .bind() realidad crea una nueva función cuyo trabajo es llamar a la función original DESPUÉS de establecer un valor personalizado de this .

Aquí hay algunas otras referencias sobre el tema:

Cómo evitar que "esto" se refiera al elemento DOM y al objeto

perfectionkills.com/know-thy-reference

¿Cómo funciona la palabra clave "this"?

Tenga en cuenta que con el uso de .apply() o .call() o .bind() , puede crear todo tipo de cosas algo extrañas y, a veces, cosas bastante útiles que nunca podrían hacerse en algo como C ++. Puede tomar cualquier función o método en el mundo y llamarlo como si fuera un método de algún otro objeto.

Por ejemplo, esto a menudo se usa para hacer una copia de los elementos en el objeto de arguments en una matriz:

var args = Array.prototype.slice.call(arguments, 0);

o similarmente:

var args = [].slice.call(arguments, 0);

Esto toma el método .slice() la matriz y lo llama, pero le proporciona un objeto de argumentos como this puntero. El objeto de arguments (aunque no es una matriz real), tiene suficiente funcionalidad similar a una matriz que el método .slice() puede operar sobre él y termina haciendo una copia de los elementos de los arguments en una matriz real que luego se puede operar directamente con operaciones de matriz real. Este tipo de artimañas no se puede hacer de ninguna manera. Si el .slice() matriz .slice() se basa en otros métodos de matriz que no están presentes en el objeto de arguments , entonces este truco no funcionaría, pero dado que solo se basa en [] y .length , los cuales tiene el objeto de arguments , en realidad funciona

Por lo tanto, este truco se puede utilizar para "tomar prestados" métodos de cualquier objeto y aplicarlos a otro objeto siempre que el objeto al que los esté aplicando sea compatible con cualquier método o propiedad que el método realmente use. Esto no se puede hacer en C ++ porque los métodos y las propiedades están "vinculados" en el momento de la compilación (incluso los métodos virtuales en C ++ están vinculados a una ubicación específica de la tabla v establecida en el momento de la compilación), pero se pueden hacer fácilmente en Javascript porque las propiedades y los métodos se buscan en vivo en tiempo de ejecución a través de su nombre real, por lo que cualquier objeto que contenga las propiedades y métodos correctos funcionará con cualquier método que opere en ellos.