导出ES6 Javascript的文件范围变量

导出ES6 Javascript的文件范围变量,javascript,ecmascript-6,es6-modules,Javascript,Ecmascript 6,Es6 Modules,接下来,我知道可能有也可能没有所谓的文件范围变量,但是,我确实记得在某个地方读过这样的术语,但除了的Q&a之外,我再也找不到了。反正 我想知道这种导出的文件范围变量的确切行为定义是什么 因为我试图动态切换我的机器人,但无法,一个接一个地消除了各种因素,最终它落在了我的头上,这是因为这些“导出的文件范围变量”,而我不理解它们的行为。请看以下极其简化的bot应用程序: VarTestFileA.js function nextBot() { BotC = !BotC return BotA[

接下来,我知道可能有也可能没有所谓的文件范围变量,但是,我确实记得在某个地方读过这样的术语,但除了的Q&a之外,我再也找不到了。反正

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

因为我试图动态切换我的机器人,但无法,一个接一个地消除了各种因素,最终它落在了我的头上,这是因为这些“导出的文件范围变量”,而我不理解它们的行为。请看以下极其简化的bot应用程序:

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,
}
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 = bt.nextBot()
bt.logBot()
console.log("O:", bt.bot)
VarTestFileB.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,
}
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 = 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 }
另外,我尝试从
VarTestFileA.js
中切换
bot
,它在其中工作,但是
console.log(“O:,bt.bot.token)
从不显示更新的值。所有的一切


这一切都归结为导出的文件范围变量的精确行为定义,因为如果将它们放在同一个文件中,它运行得非常好。因此问题就来了。

这种行为非常直截了当,同时也非常有趣。语句
const bt=require('./VarTestFileA')
创建导出对象的对象副本,我们使用变量的地方(例如
bot
)-传递值而不是引用,但传递
函数的地方传递引用,因为函数是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()
这实际上更改了
dt.bot
的值,而不是文件A中的真实
bot
。因此
bt.bot
将具有切换值,但文件A中声明的实际
bot
仍然相同,因为它没有更改。现在我们来看第三种说法:

第三句话:

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

所以这里真正的答案是,基于这种行为,我们可以声明,如果我们在文件A中保存变量的引用,那么我们可以从另一个文件中更改它们。但我真的能提供证据吗?好!是的,让我们看看下面的内容


为了测试这一点,让我们在文件A中创建另一个方法

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

function nextBot() {
    BotC = !BotC
    bot = BotA[BotC]
}
{ token: 2 }
I: { token: 3 }
O: { token: 3 }
I: { token: 2 }
O: { token: 2 }
I: { token: 3 }
O: { token: 3 }
然后导出对这些方法的引用

module.exports = {
    getBot,
    nextBot,
    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())

bt.nextBot()
bt.logBot()
console.log("O:", bt.getBot())
输出如下:

function nextBot() {
    BotC = !BotC
    bot = BotA[BotC]
}
{ token: 2 }
I: { token: 3 }
O: { token: 3 }
I: { token: 2 }
O: { token: 2 }
I: { token: 3 }
O: { token: 3 }
结果很有趣,因为现在来自文件A的
bot
似乎正在按预期进行切换


总之,问题在于通过引用或值传递属性<代码>机器人
从您的初始代码作为值传递,它不是一个复杂的项目,或者它不是声明为类型
对象
,而是作为值保存一个简单的对象。因此,无法通过引用传递
bot
。我希望得到纠正,但我不认为JavaScript中包含基本值(如
布尔值)的变量或简单对象可以通过引用传递。但函数是复杂类型,这意味着它们是
对象
s,因此它们是通过引用传递的


我希望您能找到正确的答案。

您能为每个实例提供console.log的输出吗?谢谢,让我快速解释一下为什么会发生这种行为。我不在!我花了一些时间来写答案,我有点忙,但我已经在下面提供了答案,解释了如何使用切换机器人并始终获得其更新值的行为和解决方法。始终是一个喜悦@xpt,我很高兴我能在这个主题上提供一些帮助。