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

this.property in a free function call works in my browser console and NodeJS REPL, but not when running as a NodeJS script. Why?

提问人:andres_rom 提问时间:4/30/2023 最后编辑:starballandres_rom 更新时间:6/3/2023 访问量:108

问:

我正在研究常规函数和箭头函数中的“this”关键字,因此在 Stack Overflow 中的示例之后,我认为我已经理解了这一点,但有一个细节对我来说没有解决。请帮帮我。 我不知道为什么,但是当我使用以下代码测试时,结果是,而使用Fiddle或Chrome或Firefox时,结果是预期的。node myScript.jsundefined

正如我所读到的,由于该函数是在不绑定任何对象的情况下调用的,因此它的“this”关键字指的是全局对象,并且应该打印“hi”。使用浏览器控制台或 Fiddle 不会发生,而是使用。 我不使用函数内部以避免返回,正如之前在其他 Stack Overflow 答案中解释的那样。fo2node myScript.jsconsole.log()undefined

这是代码;

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。

javascript node.js 函数 visual-studio-code 这个

评论

0赞 Wyck 5/1/2023
只是想确认您了解您在未提供对象的情况下进行调用。将你的fo2()return fo2()return this.fo2()
0赞 starball 5/1/2023
@Wyck确实,这会有所作为。但是,在这一点上,我们请不要改变这个问题,它清楚地询问了是什么导致了一种情况下的“hi”,而在另一种情况下导致了“undefined”。如果这是一个错误,那应该是它自己的问题。
0赞 andres_rom 5/2/2023
@Wyck 多亏了用户的回答,我做了一些更改,只是为了好奇,试图在节点终端(fo2()绑定全局对象)中得到正确的结果,它在package.json中使用“type”:“commonjs”到达那里,并分配了问候语顶部变量,如globalThis.greeting = 'hi'

答:

4赞 starball 5/1/2023 #1

这里正在发生几件事。

一个是当你运行一个脚本时,该脚本是作为一个“模块”运行的。如果您的package.json有 ,或者没有指定该字段,则它将作为 CommonJS 模块运行。如果您的package.json有 ,它将作为 ECMAScript 模块运行。(相关文档)。也就是说,如果您用作文件扩展名。如果使用 ,NodeJS 会将其视为 CommonJS 模块,如果使用 ,NodeJS 会将其视为 ECMAScript 模块。(相关文档)。node myScript.js"type": "commonjs""type""type": "module".js.cjs.mjs

另请参阅 REPL 和脚本之间的“this”区别。The TL;DR 是使用 CommonJS 模块,模块中的代码就像包装在以下内容中一样运行:

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

但是,如果您在 REPL 模式下运行 NodeJS(只需在系统控制台中运行),则 is 和在“顶级范围”中声明的变量将被放置在对象中,就像它们在浏览器控制台中一样(其中与全局对象同义)。nodethis === globalThistruevarglobalThisglobalThiswindow

在浏览器控制台中,您会收到“hi”,因为调用您的函数时没有给出特定的 ,因此它回退到 .但是在 ECMAScript 模块上下文中(例如,NodeJS 脚本使用带有 的 package.json 或 web(模块脚本))运行),顶层始终是 .console.log(this.greeting)thisglobalThis"type": "module"<script module>thisundefined

另一件事是,如果不指定严格模式,JavaScript 通常会默认以“草率模式”运行,其中 never .严格模式通常是选择加入的,但在 ECMAScript 模块上下文中,严格模式是默认模式。这就是为什么你在运行时会遇到错误,如果你做了一些事情来启用严格模式,你实际上会得到一个错误。thisundefinedundefinednode myScript.js

以下是在启用严格模式的情况下运行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);

如果您放入 package.json,则在不显式使用的情况下运行上述代码时会遇到相同的错误。"use strict";"type": "module"

更多阅读:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this