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.
-
Llamada de función normal: en una llamada de función normal como
foo()
, se establece en el objeto global (que es unawindow
en un navegador) o enundefined
(en el modo estricto de Javascript). -
Llamada de método: si se llama a un método como
obj.foo()
, entonces se establece enobj
dentro de la función. -
.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 hacerfoo.call(myObj)
y hacer quethis
se establezca enmyObj
dentro defoo()
para esa llamada de función en particular. -
Uso de new: si llama a una función con
new
comonew foo()
, se crea un nuevo objeto y se llama a la función constructorafoo
conthis
conjunto al objeto recién creado. -
Uso de .bind (): al usar
.bind()
, se devuelve una nueva función de código auxiliar de esa llamada que usa internamente.apply()
para establecerthis
puntero como se pasó a.bind()
. FYI, este no es realmente un caso diferente porque.bind()
se puede implementar con.apply()
. -
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.