ES6 Javascript的导出文件范围变量

问题描述

紧随What is file scope in javascript之后,我知道可能存在或可能没有所谓的“文件范围变量”,但是我确实记得在某处读过该术语,但除了找不到以外,再也找不到它了。 What is file scope in javascript的问答。无论如何,

我想知道这种导出的文件范围变量的确切行为定义是什么。

因为我试图动态地切换我的机器人,但是却无法一一消除,最终导致我失望的原因是因为这种“导出的文件范围变量”,而我却不了解它们的行为。看一下以下极其简化的机器人应用程序:

VarTestFileA.js

function nextBot() {
  BotC = !BotC
  return BotA[BotC]
}

function logBot() {
  console.log("I:",bot)
}

const BotA = {true: {"token": 2},false: {"token":3}}
let BotC = true

var bot = BotA[BotC]

module.exports = {
  bot,nextBot,logBot,}

VarTestFileB.js

const bt = require('./VarTestFileA')

console.log(bt.bot)

bt.bot = bt.nextBot()
bt.logBot()
console.log("O:",bt.bot)

bt.bot = bt.nextBot()
bt.logBot()
console.log("O:",bt.bot)

您可能知道(即使不运行它)无论我怎么做,bt.bot都无法切换。输出为:

$ node VarTestFileB.js
{ token: 2 }
I: { token: 2 }
O: { token: 3 }
I: { token: 2 }
O: { token: 2 }
I: { token: 2 }
O: { token: 3 }

此外,我尝试从bot内部切换VarTestFileA.js,在其中工作,但console.log("O:",bt.bot.token)从未显示更新后的值。所有,所有

所有这些都归结为此类导出文件作用域变量的确切行为定义,因为如果将它们放在同一文件中,它将运行得很好。因此是问题。

解决方法

这种行为非常简单,同时又很有趣。语句const bt = require('./VarTestFileA')创建导出对象的对象副本,在此我们使用了变量(例如bot)-传递值而不是引用,但是在传递Function然后引用因为函数是JS中的对象而被传递。

我们从 VarTestFileA.js 中导出了{ bot,nextBot,logBot },因此dt实际上等于:

dt = {
  bot : bot,//copy of old bot = BotA[BotC] which equals {"token": 2} 
  nextBot: nextBot,//reference to nextBot() which has access to bot in file A
  nextBot: logBot,//reference to logBot () which has access to bot in file A
}

现在进入 VarTestFileB.js ,我们在其中打印并尝试了解其行为,让我们看一下每个语句的行为:

第一句话:

console.log(bt.bot)将打印{"token": 2},因为bot是按值而不是引用传递的。

第二条声明:

bt.bot = bt.nextBot()实际上会更改文件A中的dt.bot而不是真实的bot的值。因此bt.bot将具有切换后的值,但实际的{{1}在文件A中声明的}仍然相同,因为它没有被更改。现在,我们进入第三条语句:

第三条声明:

bot,这将打印文件A中的bt.logBot()的初始值。因为它没有被更改。

因此,真正的答案是,基于此行为,我们可以声明,如果我们在文件A中保存变量的引用,则可以从另一个文件中更改它们。但是我真的可以为此提供证据吗?好!是的,让我们看看下面的情况


要对此进行测试,让我们在文件A中创建另一个方法;

bot

然后按如下所示修改function getBot(){ return bot; }

nextBot

,然后导出对这些方法的引用;

function nextBot() {
    BotC = !BotC
    bot = BotA[BotC]
}

所以我们现在可以执行相同的实验,并尝试从问题中打印出旧的测试:

module.exports = {
    getBot,logBot,}

输出如下:

const bt = require('./VarTestFileA')
console.log(bt.getBot())

bt.nextBot()
bt.logBot()
console.log("O:",bt.getBot())

bt.nextBot()
bt.logBot()
console.log("O:",bt.getBot())

结果有趣,因为现在文件A中的{ token: 2 } I: { token: 3 } O: { token: 3 } I: { token: 2 } O: { token: 2 } I: { token: 3 } O: { token: 3 } 似乎在按预期方式切换。


最后,问题在于通过引用或值传递属性。初始代码中的bot是按值传递的,它不是一个复杂的项目,也不是声明为类型bot,而是将一个简单的对象作为值。因此,无法通过引用传递Object。我的立场是正确的,但我不认为JavaScript中包含bot之类的原始值的变量或简单对象,因为值可以通过引用传递。但是函数是复杂类型,意味着它们是Boolean,因此它们是通过引用传递的。

希望您能按顺序找到它。