this.property 在我的浏览器控制台和NodeJS REPL中可以工作,但在作为NodeJS脚本运行时则不行,为什么?

pw136qt2  于 2023-05-06  发布在  Node.js
关注(0)|答案(1)|浏览(114)

我正在研究常规函数和箭头函数中的'this'关键字,所以在Stack Overflow中的示例中,我认为我已经理解了这一点,但还有一个细节没有解决。请帮帮我我不知道为什么,但是当我使用node myScript.js测试下面的代码时,结果是undefined,而使用Fiddle或Chrome或Firefox时,结果是预期的。
正如我所读到的,因为fo2函数是在没有绑定任何对象的情况下调用的,所以它的'this'关键字是指全局对象,而'hi'应该被打印出来。使用node myScript.js不会发生这种情况,但使用浏览器控制台或Fiddle会发生这种情况。我没有在函数内部使用console.log(),以避免返回undefined,因为它已经在其他Stack Overflow答案中解释过了。
这是代码;

var greeting = 'hi';

const obj = {
  greeting: 'hey',

  fo() {
    const greeting = 'hello';

      function fo2 () {
        return this.greeting;
      };
      
      return fo2();  
  }  
};

console.log(obj.fo()); // 'hi' using browser console and Fiddle, but undefined using `node myScript.js`

我使用的是NodeJS 18.12.1。

au9on6nz

au9on6nz1#

这里有几件事。
一个是当您运行像node myScript.js这样的脚本时,脚本是作为“模块”运行的。如果你的package.json有"type": "commonjs",或者没有指定"type"字段,它将作为CommonJS模块运行。如果你的package.json有"type": "module",它将作为ECMAScript模块运行。(相关文档)。也就是说,如果您使用.js作为文件扩展名。如果你使用.cjs,NodeJS会将其视为CommonJS模块,如果你使用.mjs,NodeJS会将其视为ECMAScript模块。(相关文档)。
参见'this' different between REPL and script。TL;DR是使用CommonJS模块,模块中的代码运行时就像它被 Package 在下面的代码中一样:

var ctx = {};
(function(exports) {
    // your code
    console.log(this === globalThis); // false
}).call(ctx, ctx);

但是如果你在REPL模式下运行NodeJS(只在系统控制台中运行node),那么this === globalThis就是true,并且在“顶级作用域”中用var声明的变量将被放置在globalThis对象中,就像它们在浏览器控制台中一样(其中globalThis与全局window对象同义)。
在您的浏览器控制台中,您会得到“hi”,因为您调用console.log(this.greeting)的函数没有给定特定的this,因此它福尔斯到globalThis。但是在ECMAScript模块上下文中(例如:NodeJS脚本使用package.json和"type": "module"或web <script module>(模块脚本)运行,顶层的this始终是undefined
另一件事是,如果您不指定strict mode,JavaScript通常会默认在"sloppy mode"中运行,其中this永远不会是undefined。严格模式通常是可选的,但在ECMAScript模块上下文中,严格模式是默认模式。这就是为什么在运行node myScript.js时会得到undefined,而如果启用严格模式,实际上会得到一个错误。
下面是在启用严格模式的情况下运行CommonJS模块的“幕后”情况(如果您将"use strict";放在脚本文件的顶部):

let ctx = {};
(function() {
  "use strict";
  function a(){
    console.log(this.foo);
  }
  a(); // Uncaught TypeError: Cannot read properties of undefined (reading 'foo')
}).call(ctx);

如果您将"type": "module"放入package.json中,则在没有显式使用"use script";的情况下运行上述代码时会出现相同的错误。
更多阅读:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

相关问题