2012-02-28 16 views
10

He estado jugando con node.js últimamente y me encontré con un comportamiento extraño sobre el uso de this en el alcance global de un módulo.node.js: Uso confuso de 'esto' en el ámbito global

this está obligado a module.exports en el ámbito global:

console.log(this === exports); // -> true 

Pero this está obligado a global en un ámbito de método:

(function() { console.log(this === global); })(); // -> true 

Esto también conducen a este comportamiento confuso:

this.Foo = "Weird"; 
console.log(Foo); // -> throws undefined 

(function() { this.Bar = "Weird"; })(); 
console.log(Bar); // -> "Weird" 

Supongo que la solución es t o nunca use this en el alcance global y explícitamente use extends o global en su lugar, pero ¿hay una lógica detrás de todo esto o es un error o una limitación en node.js?

Respuesta

1

Al trabajar en una implementación simple de módulos CommonJS, tuve que pensar qué hacer con this en el alcance global del módulo; no está dirigido por la especificación.

También configurarlo como el objeto exports al principio, porque pensé que sería útil, pero más tarde found some code que necesitaba "modulize" que utilizaba this para obtener un identificador para el objeto global, por lo que cambió this volver al objeto global para proporcionar un entorno lo más cercano posible a "normal" para el código del módulo.

Sólo podemos adivinar en qué nodo se establece la forma en que está (o pedir al autor), pero mi conjetura es que se hizo simplemente porque parecía una idea útil, similar a la forma en que puede dar a la module objetar una propiedad exports en el nodo y hacer que se refleje en el exports real del módulo (este comportamiento tampoco forma parte de la especificación, pero tampoco va en contra).

En cuanto a la parte de su pregunta acerca this referencia global en funciones, como las otras respuestas explican, eso es sólo la forma en this obras; no es un comportamiento específico del nodo, es un comportamiento extraño de JavaScript.

7

La "lógica" detrás de esto es, que el valor de this siempre depende de cómo se invoca una función.

En su caso, tiene una función anónima autoejecutable, allí, this siempre hace referencia al objeto global (modo no estricto) o undefined (ES5 estricto).

Si desea acceder a la this valor "exterior", que bien podría almacenar una referencia antes de ejecutar esa función, como

var outerScope = this; 

(function() { outerScope.Bar = "Weird"; })(); 
console.log(Foo); // -> throws undefined 

o volver a la .bind() funciones alcance a sí mismo, como

(function() { this.Bar = "Weird"; }).bind(this)(); 
+1

¿No sería menos confuso si 'this' en el alcance global estuviera ligado a' global' en vez de 'extends' entonces? Esperaría que "esto" significara lo mismo en el ámbito global y en el alcance de una función estática. –

+0

@SelflessCoder: Honestamente, no sé por qué esto está ligado al objeto 'exports'. Pero, en general, es una buena idea NO derrotar al objeto global con datos. Por lo tanto, solo tenga en cuenta que cualquier contexto de función puede tener un valor 'this' diferente, dependiendo de cómo se llame. – jAndy

+0

Como dice jAndy, esto es básicamente cómo 'this' funciona en javascript. No he leído ninguna discusión al respecto, pero supongo que tener 'this === exports' en alcance global se supone que es análogo a' this === window' en el alcance global de un navegador. IMO, teniendo 'this === global' en alcance global tiene menos sentido, ya que eso significaría que' this.foo === foo'. –

1

No sé si esta es la intención exacta del equipo de Node.js, pero me sorprendería que no fuera así. Considere que este ejemplo se ejecutó en la consola de desarrollo de un navegador (p.cromo):

var x = function(){console.log(this)} 
a = {} 
a.x = x 
a.xx = function(){x()} 

a.x() 
>> Object 
a.xx() 
>> DOMWindow 
x() 
>> DOMWindow 

como se puede ver la ejecución de un método sin especificar su contexto establece el contexto para ser el global. En este caso, el objeto DOMWindow.

Cuando está dentro de un módulo, su contexto es el módulo, pero ejecuta un método sin especificar un contexto con .call o .apply u obj. usará el contexto global, global, en lugar del local, module.exports.

Cuestiones relacionadas