Significado de “esto” en los módulos y funciones de node.js

Tengo un archivo JavaScript que se carga por require .

 // loaded by require() var a = this; // "this" is an empty object this.anObject = {name:"An object"}; var aFunction = function() { var innerThis = this; // "this" is node global object }; aFunction(); (function(anyParameter){ console.log(anyParameter.anObject); })( this // "this" is same having anObject. Not "global" ); 

Mi pregunta es: this en var a = this; es un objeto vacío, mientras que this declaraciones en funciones son sombras del objeto global node.js. Sé que this palabra clave es diferente en funciones, pero no podía entender por qué primero this no es igual a global y this en funciones es igual a global.

¿Cómo inyecta node.js global a this en los ámbitos de función, y por qué no lo inyecta al ámbito de módulo?

Aquí hay algunos datos fundamentales que debe comprender para aclarar la situación:

  • En el código de nivel superior en un módulo de nodo, this es equivalente a module.exports . Ese es el objeto vacío que ves.

  • Cuando usa this dentro de una función, el valor de this se determina de nuevo antes de cada ejecución de la función, y su valor se determina por la forma en que se ejecuta la función . Esto significa que dos invocaciones del mismo objeto de función podrían tener valores diferentes si los mecanismos de invocación aFunction() diferentes (por ejemplo, aFunction() vs. aFunction.call(newThis) vs. emitter.addEventListener("someEvent", aFunction); etc. .) En su caso, aFunction() en modo no estricto ejecuta la función con this conjunto en el objeto global.

  • Cuando los archivos JavaScript se require como módulos de nodo, el motor de nodo ejecuta el código del módulo dentro de una función de contenedor. Esa función de ajuste de módulo se invoca con a this conjunto en module.exports . (Recuerde, arriba, una función puede ejecutarse con un valor máximo de this valor.)

Por lo tanto, obtienes valores diferentes porque cada uno reside dentro de una función diferente: el primero está dentro de la función de envoltura de módulo creada por Node y el segundo está dentro de aFunction .

Para comprender esto, debe comprender que Node.js realmente envuelve el código de su módulo en una función, como esta

 (function (exports, require, module, __filename, __dirname) { var test = function(){ console.log('From test: ' + this); }; console.log(this); test(); }); 

La explicación detallada se puede encontrar en esta respuesta .


Ahora, esta función envuelta es invocada de esta manera

 var args = [self.exports, require, self, filename, dirname]; return compiledWrapper.apply(self.exports, args); 

Por lo tanto, this , a nivel de módulo, es en realidad el objeto de exports .

Puedes confirmar que así

 console.log(this, this === module.exports); // {} true 

Resumen:

En Javascript, el valor de this se determina cuando se llama a una función . No cuando se crea una función. En nodeJS, en el ámbito más externo de un módulo, el valor de this es el objeto module.exports actual. Cuando se llama a una función como una propiedad de un objeto, el valor de esto cambia al objeto que fue llamado. Puedes recordar esto simplemente por la regla de la izquierda del punto :

Cuando se llama a una función, puede determinar el valor de this mirando el lugar de la invocación de la función. El objeto a la izquierda del punto es el valor de this . Si no hay ningún objeto a la izquierda del punto, el valor de this es el objeto module.exports ( window en los navegadores).

advertencias

  • Esta regla no se aplica a la función de flecha es2015 que no tiene su propio enlace de this .
  • Las funciones call , apply y bind pueden doblar las reglas con respecto a this valor.

Ejemplo (NodeJS):

 console.log(this); // {} , this === module.exports which is an empty object for now module.exports.foo = 5; console.log(this); // { foo:5 } let obj = { func1: function () { console.log(this); }, func2: () => { console.log(this); } } obj.func1(); // obj is left of the dot, so this is obj obj.func2(); // arrow function don't have their own this // binding, so this is module.exports, which is{ foo:5 } 

Salida:

introduzca la descripción de la imagen aquí

Esto se debe a que el objeto global predeterminado en un módulo Node.js es el objeto de exports , y está llamando a test() que no especifica this . En JS tradicional, this apunta al objeto global, con un use strict , this será nulo.

this puede apuntar a cualquier cosa, solo depende de cómo lo llames.

  • test() : utiliza el objeto global ( exports ) como this , a menos que sea en modo estricto, donde this será nulo;
  • test.call({}) o test.apply({}) : está especificando qué usar como this (el primer parámetro)
  • var obj = {testRef: test}; obj.testRef() var obj = {testRef: test}; obj.testRef() : this se establece a la izquierda de . , eso es, obj

Contrarrestando la respuesta de los cuatro ojos

Es cierto que this en el nivel superior del módulo son las exports , pero eso no significa necesariamente que this test() interna test() también apunte a lo mismo desde donde se llamó.


Intentando probar que this y el objeto global apuntan a exports

  myGLobal = 5; this.myGlobal; // 5