问题描述
紧随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
,因此它们是通过引用传递的。
希望您能按顺序找到它。