Acabo de encontrar una situación interesante en JavaScript. Tengo una clase con un método que define varios objetos usando notación literal de objeto. Dentro de esos objetos, this
se está utilizando el puntero. Por el comportamiento del programa, deduje que el this
puntero se refiere a la clase en la que se invocó el método, y no al objeto creado por el literal.
Esto parece arbitrario, aunque es la forma en que esperaría que funcione. ¿Es este comportamiento definido? ¿Es seguro para todos los navegadores? ¿Hay algún razonamiento subyacente por qué está más allá de lo que dice "la especificación lo dice" (por ejemplo, ¿es consecuencia de alguna decisión / filosofía de diseño más amplia)? Ejemplo de código reducido:
// inside class definition, itself an object literal, we have this function:
onRender: function() {
this.menuItems = this.menuItems.concat([
{
text: 'Group by Module',
rptletdiv: this
},
{
text: 'Group by Status',
rptletdiv: this
}]);
// etc
}
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};
Respuestas:
Canibalizado de otra publicación mía, aquí hay más de lo que siempre quisiste saber sobre esto .
Antes de comenzar, esto es lo más importante que debe tener en cuenta sobre Javascript, y repetirse a sí mismo cuando no tiene sentido. Javascript no tiene clases (ES6
class
es azúcar sintáctico ). Si algo parece una clase, es un truco inteligente. Javascript tiene objetos y funciones . (eso no es 100% preciso, las funciones son solo objetos, pero a veces puede ser útil pensar en ellas como cosas separadas)La variable this está asociada a funciones. Cada vez que se invoca una función, esto se da un cierto valor, dependiendo de cómo se invoca la función. Esto a menudo se llama patrón de invocación.
Hay cuatro formas de invocar funciones en javascript. Puede invocar la función como método , como función , como constructor y con apply .
Como un método
Un método es una función adjunta a un objeto.
Cuando se invoca como un método, este se enlaza con el objeto de la función / método es una parte de. En este ejemplo, esto estará obligado a engañar.
Como una función
Si tiene una función independiente, esta variable estará vinculada al objeto "global", casi siempre el objeto de ventana en el contexto de un navegador.
Esto puede ser lo que te hace tropezar , pero no te sientas mal. Muchas personas consideran que esta es una mala decisión de diseño. Dado que una devolución de llamada se invoca como una función y no como un método, es por eso que está viendo lo que parece ser un comportamiento inconsistente.
Muchas personas solucionan el problema haciendo algo como, um, esto
Define una variable que apunta a esto . Cierre (un tema de todo es propio) mantiene que los rodea, por lo que si se llama a la barra como una devolución de llamada, todavía tiene una referencia.
NOTA: en
use strict
modo si se usa como función,this
no está vinculado a global. (Lo esundefined
)Como constructor
También puede invocar una función como constructor. Según la convención de nomenclatura que está utilizando (TestObject), esto también puede ser lo que está haciendo y lo que lo está tropezando .
Invoca una función como Constructor con la nueva palabra clave.
Cuando se invoca como un constructor, se creará un nuevo objeto, y este estará obligado a ese objeto. Nuevamente, si tiene funciones internas y se usan como devoluciones de llamada, las invocará como funciones, y esto estará vinculado al objeto global. Usa esa var that = este truco / patrón.
Algunas personas piensan que el constructor / nueva palabra clave fue un hueso lanzado a los programadores tradicionales de Java / OOP como una forma de crear algo similar a las clases.
Con el método Apply
Finalmente, cada función tiene un método (sí, las funciones son objetos en Javascript) llamado "aplicar". Aplicar le permite determinar cuál será el valor de esto , y también le permite pasar una serie de argumentos. Aquí hay un ejemplo inútil.
fuente
this
seráundefined
para invocaciones de funciones.this
no tiene nada que ver con el alcance. Te refieres al objeto global .this.confusing = 'hell yeah';
lo mismo quevar confusing = 'hell yeah';
? Entonces, ¿ambos permitiránmyObject.confusing
? Sería bueno si no solo para que pueda usarthis
para crear las propiedades y otras variables para el trabajo interno.function Foo(thought){ this.confusing = thought; }
y luegovar myObject = new Foo("hell yeah");
Llamadas a funciones
Las funciones son solo un tipo de objeto.
Todos los objetos de función tienen métodos de llamada y aplicación que ejecutan el objeto de función al que están llamados.
Cuando se llama, el primer argumento de estos métodos especifica el objeto al que hará referencia la
this
palabra clave durante la ejecución de la función, si se usanull
oundefined
, el objeto global,window
parathis
.Por lo tanto, llamando a una función ...
... con paréntesis -
foo()
- es equivalente afoo.call(undefined)
ofoo.apply(undefined)
, que es efectivamente el mismo quefoo.call(window)
ofoo.apply(window)
.Los argumentos adicionales a
call
se pasan como argumentos a la llamada a la función, mientras que un único argumento adicional aapply
puede especificar los argumentos para la llamada a la función como un objeto tipo Array.Por lo tanto,
foo(1, 2, 3)
es equivalente afoo.call(null, 1, 2, 3)
ofoo.apply(null, [1, 2, 3])
.Si una función es propiedad de un objeto ...
... acceder a una referencia a la Función a través del objeto y llamarla entre paréntesis -
obj.foo()
- es equivalentefoo.call(obj)
ofoo.apply(obj)
.Sin embargo, las funciones mantenidas como propiedades de los objetos no están "vinculadas" a esos objetos. Como puede ver en la definición de
obj
arriba, dado que las funciones son solo un tipo de objeto, se pueden hacer referencia a ellas (y, por lo tanto, se pueden pasar por referencia a una llamada de función o devolverse por referencia desde una llamada de función). Cuando se pasa una referencia a una Función, no se lleva información adicional sobre el lugar desde el que se pasó, por lo que sucede lo siguiente:La llamada a nuestra referencia de función,
baz
no proporciona ningún contexto para la llamada, por lo que es efectivamente igual quebaz.call(undefined)
, por lo quethis
termina haciendo referenciawindow
. Si queremosbaz
saber que perteneceobj
, de alguna manera debemos proporcionar esa información cuandobaz
se llama, que es donde entra en juego el primer argumentocall
oapply
cierre.Cadenas de alcance
Cuando se ejecuta una función, crea un nuevo ámbito y tiene una referencia a cualquier ámbito de inclusión. Cuando se crea la función anónima en el ejemplo anterior, tiene una referencia al ámbito en el que se creó, que es
bind
el ámbito. Esto se conoce como un "cierre".Cuando intente acceder a una variable, se recorre esta "cadena de alcance" para encontrar una variable con el nombre dado: si el alcance actual no contiene la variable, observe el siguiente alcance en la cadena, y así sucesivamente hasta llegar a El alcance global. Cuando se devuelve la función anónima y
bind
termina de ejecutarse, la función anónima aún tiene una referencia albind
alcance de la aplicación, por lo quebind
el alcance no "desaparece".Dado todo lo anterior, ahora debería poder comprender cómo funciona el alcance en el siguiente ejemplo, y por qué la técnica para pasar una función alrededor de "pre-enlazado" con un valor particular de la
this
misma tendrá lugar cuando se llama funciona:fuente
Si. Y si.
El significado de
this
es bastante simple de deducir:this
se usa dentro de una función constructora, y la función se invocó con lanew
palabra clave, sethis
refiere al objeto que se creará.this
seguirá significando el objeto incluso en métodos públicos.this
se usa en cualquier otro lugar, incluidas las funciones protegidas anidadas , se refiere al alcance global (que en el caso del navegador es el objeto de ventana).El segundo caso es obviamente un defecto de diseño, pero es bastante fácil solucionarlo utilizando cierres.
fuente
En este caso, el interno
this
está vinculado al objeto global en lugar de a lathis
variable de la función externa. Es la forma en que está diseñado el lenguaje.Consulte "JavaScript: las partes buenas" de Douglas Crockford para obtener una buena explicación.
fuente
Encontré un buen tutorial sobre el ECMAScript esto
Cualquier objeto puede usarse como este valor del contexto.
Esta característica es muy importante, porque a diferencia de las variables, este valor nunca participa en el proceso de resolución del identificador. Es decir, al acceder a esto en un código, su valor se toma directamente del contexto de ejecución y sin ninguna búsqueda de cadena de alcance. El valor de esto se determina solo una vez al ingresar al contexto.
En el contexto global, un valor de este es el objeto global en sí mismo (es decir, este valor aquí es igual a un objeto variable)
En el caso de un contexto de función, este valor en cada llamada de función puede ser diferente
Referencia Javascript-the-core y Capítulo-3-this
fuente