【问题标题】:Exported File Scope Variables of ES6 JavascriptES6 Javascript 的导出文件范围变量
【发布时间】:2020-08-28 20:40:49
【问题描述】:

跟进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 = 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) 从未显示更新的值。万事如意,

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

【问题讨论】:

  • 能否请您包含每个实例的 console.log 输出?
  • 谢谢,让我快速解释一下为什么会发生这种行为。我走了!
  • 我花了一些时间来写答案,我有点忙,但我在下面提供了答案,解释了如何使用切换机器人并始终获得更新值的行为和解决方法.

标签: javascript ecmascript-6 es6-modules


【解决方案1】:

这种行为非常直接,同时也非常有趣。语句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()这实际上改变了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]
}

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

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())

输出如下:

{ token: 2 }
I: { token: 3 }
O: { token: 3 }
I: { token: 2 }
O: { token: 2 }
I: { token: 3 }
O: { token: 3 }

结果很有趣,因为现在文件 A 中的 bot 似乎按预期切换。


在结论中,问题是通过引用或值传递属性。初始代码中的bot 是按值传递的,它不是一个复杂的项目,或者它没有声明为Object 类型,而是将一个简单的对象作为值。所以没有办法通过引用传递bot。我有待纠正,但我不认为拥有原始值的变量(如 JavaScript 中的 Boolean 或作为值的简单对象)可以通过引用传递。但是函数是复杂类型,也就是说它们是Objects,因此它们是通过引用传递的。

我希望你能按顺序找到这个。

【讨论】:

  • 总是很高兴@xpt,我很高兴我能制作一些有助于这个主题的东西。
猜你喜欢
  • 2022-11-17
  • 2017-07-07
  • 1970-01-01
  • 1970-01-01
  • 2016-11-30
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 2020-02-07
相关资源
最近更新 更多