Le mot-clé 'this' se comporte différemment dans Nodejs et navigateur

J'ai ce code:

var obj1; var obj2; function x() { obj1 = this; } function y() { obj2 = this; } x(); y(); console.log(obj1 === obj2); console.log(obj1 === this); 

J'ai exécuté ce code dans NodeJS à l'aide de la ligne de commande: node app.js et exécuté en tant que script dans le navigateur Chrome

Le résultat: dans NodeJS, le résultat était: true false NodeJS result

Dans le navigateur Chrome, le résultat était: true true Browser result

Comment cela s'est-il passé? Quelqu'un peut-il expliquer ce qui se passe réellement sous le capot?

Dans le navigateur, en cours d'exécution dans la portée globale, c'est toujours une window dans votre exemple

 var obj1; var obj2; function x() { obj1 = this; // window } function y() { obj2 = this; // window } x(); y(); console.log(obj1 === obj2); // window === window = true console.log(obj1 === this); // window === window = true 

Ce n'est pas comme ça fonctionne dans Node. Dans Node.js, tous les modules (fichiers de script) sont exécutés dans leur propre fermeture tandis que les navigateurs exécutent tous les fichiers de script directement dans la portée globale.

En d'autres termes, à peu près n'importe quel fichier exécuté dans Node, this sera simplement un objet vide, car Node enveloppe le code dans une fonction anonyme appelée immédiatement et vous accédez à la portée globale dans ce contexte avec GLOBAL place.

Ceci est également mentionné dans la documentation Globals :

Certains de ces objets ne sont pas dans la portée globale, mais dans la portée du module – cela sera noté.

Cependant, lorsque vous appelez une fonction sans contexte spécifique dans Node.js, il sera normalement définitivement défini sur l' objet global – Le même GLOBAL mentionné précédemment, car il est un contexte d'exécution.

Ainsi, en dehors des fonctions, this s'agit d'un objet vide, car le code est enveloppé dans une fonction par Node, pour créer son propre contexte d'exécution pour chaque module (fichier de script), alors que dans les fonctions, car ils sont appelés sans contexte d'exécution spécifié , this l'objet Node GLOBAL

Dans Node.js, vous obtiendriez

 var obj1; var obj2; function x() { obj1 = this; // GLOBAL } function y() { obj2 = this; // GLOBAL } x(); y(); console.log(obj1 === obj2); // GLOBAL === GLOBAL = true console.log(obj1 === this); // GLOBAL === {} = false 

Où le dernier est-il effectivement un objet vide, comme expliqué ci-dessus


Pour l'exhaustivité, il convient de noter que, dans un mode strict, vous obtenez le même résultat dans un navigateur ( true, false ) que dans Node, mais c'est parce que les variables sont tout le contraire de ce qu'elles sont dans Node

 "use strict" var obj1; var obj2; function x() { obj1 = this; // undefined } function y() { obj2 = this; // undefined } x(); y(); console.log(obj1 === obj2); // undefined === undefined = true console.log(obj1 === this); // undefined === window = false 

C'est parce que la valeur passée comme this à une fonction en mode strict n'est pas forcée à être un objet (aka "boxed").
Pour une fonction normale en mode non stricte, c'est toujours un objet, et c'est toujours l'objet global s'il est appelé avec une valeur-valeur undefined ou null c'est-à-dire sans contexte d'exécution spécifique.

Non seulement la boxe automatique est un coût de performance, mais exposer l'objet global dans les navigateurs est un danger pour la sécurité, car l'objet global permet d'accéder à la fonctionnalité que les environnements JavaScript "sécurisés" doivent restreindre.

Ainsi, pour une fonction de mode stricte, la spécification n'est pas encadrée dans un objet et, si elle n'est pas spécifiée, this ne sera pas undefined dans les fonctions internes, comme indiqué ci-dessus, mais this sera toujours la fenêtre dans la portée globale.

La même chose se produit dans le mode strict dans Node.js, où this fonction n'est plus GLOBAL mais undefined , et this dehors des fonctions sera toujours le même objet vide, et le résultat final sera toujours true, false , mais La valeur de this sera différente en mode strict dans Node.js également.

Le noeud définit explicitement this aux exportations de modules ici :

 const result = compiledWrapper.apply(this.exports, args); 

Ce qui apply c'est de fixer explicitement this valeur (et les paramètres) – dans ce cas – il le définit sur this.exports . Par exemple, vous pouvez le faire:

 (function() { console.log(this.x); }).apply({x:3}); // alerts 3 

La substitution par nœud est le comportement par défaut. Il faut cependant appeler des fonctions à l'intérieur de l'objet avec global – comme le prescrit la spécification JS.

Dans le contexte du navigateur, le dernier point indique l'objet Window, qui existe dans Node-Context. Par conséquent, le dernier est un objet vide. Les occurrences de ceci dans les fonctions indiquent cependant un objet global dans le contexte de nœud.

La différence est assez simple

Dans l'environnement de noeud:

Cela se réfère à module.exports ou à des exports à court terme. Mais à l'intérieur d'une fonction, cela se rapporte à l'ensemble du paquet Node.js.

Vous pouvez le voir si vous vous connectez à la console comme suit:

 function test(){ console.log('this inside a function = ',this); } console.log('this outside a function = ',this); test(); 

Alors que dans l'environnement du navigateur, ceci dans une fonction ou à l'extérieur d'une fonction fait référence à l' objet de la fenêtre, sauf si vous utilisez le nouveau mot-clé qui est une autre histoire.

Exécutez l'exemple précédent dans Node.js et les environnements de navigateur et vous comprendrez.

Je n'ai pas de serveur Node.js dans une main maintenant, mais je pense que vous pouvez vous-même rechercher cette question et répondre à nous: D voir le code ci-dessous

Essayez d'exécuter:

console.log(this.constructor.name+" "+obj1.constructor.name+" "+obj2.constructor.name);

Et vous pouvez également déboguer le nom "Parent Class" dans une fonction:

 function x() { console.log("x this: "+this.constructor.name); obj1 = this; } function y() { console.log("y this: "+this.constructor.name); obj2 = this; } 

Et pour voir les méthodes / propriétés d'objet, vous pouvez utiliser quelque chose comme ceci:

 for (a in obj2) { console.log("obj2." + a + " = " + obj2[a]); }