I am new to JavaScript and trying to make a simple node server. Here is my code:
我是JavaScript新手,尝试创建一个简单的节点服务器。这是我的代码:
var activeGames = {}
exports.initialize = function(){
var gameID = "game12345"
activeGames.gameID = new Game(gameID, "player1", "player2")
}
I call the initialize function from another module, and I get an error stating that activeGames is undefined. activeGames is at the outermost scope of the file. I tried adding 'this' before activeGames.gameID but that did not fix it. Why is activeGames undefined? Thanks in advance.
我从另一个模块调用initialize函数,我得到一个错误,说明activeGames没有定义。activeGames位于文件的最外层。我试着在activeGames之前添加“this”。但这并不能解决问题。为什么activeGames定义?提前谢谢。
EDIT: Here's how I'm calling this code.
编辑:这是我如何调用这个代码。
In my base index file I have
在我的基本索引文件中
const handler = require("./request-handler.js")
handler.initialize()
In request-handler.js, I have
在请求处理程序。js,我
var gameManager = require('./game-manager')
exports.initialize = function(){
gameManager.initialize()
}
3 个解决方案
#1
1
JavaScript has lexical scope, not dynamic scope. ref: https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scoping
JavaScript有词法范围,而不是动态范围。裁判:https://en.wikipedia.org/wiki/Scope_(computer_science)# Lexical_scoping
Lexical scope means that whether a variable is accessible or not depends on where they appear in the source text, it doesn't depend on runtime information.
词法作用域意味着变量是否可访问取决于它们在源文本中的位置,它不依赖于运行时信息。
example:
例子:
function foo() {
var bar = 42;
baz();
}
function baz() {
console.log(bar); // error because bar is not in the scope of baz
}
the same problem happens in your code,
同样的问题也发生在你的代码中,
var activeGames
var activeGames
is not in scope.
不在范围内。
try this variation:
试试这种变化:
exports.initialize = function(){
var activeGames = {}
var gameID = "game12345"
activeGames.gameID = new Game(gameID, "player1", "player2")
}
A good solution could be to use a class and export it: --THIS CODE IS NOT TESTED--
一个好的解决方案可能是使用一个类并将其导出:—此代码没有经过测试—
class gamesManager {
var activeGames = {}
initialize() {
var gameID = "game12345"
activeGames.gameID = new Game(gameID, "player1", "player2")
}
}
exports.gamesManager = gamesManager
USE:
使用:
const activeGames = require('./game-manager');
const activeGamesInstance = new activeGames.gamesManager();
activeGamesInstance.initialize();
#2
1
Need a code sample for this one. I ran this locally and it worked fine, although your code has a big issue which may be a part of your problem. It looks like you want to keep track of multiple games in activeGames
. You need to use this syntax instead:
为此需要一个代码示例。我在本地运行这个程序,它运行得很好,尽管您的代码有一个很大的问题,这可能是问题的一部分。看起来你想在活动游戏中跟踪多个游戏。你需要使用这种语法来代替:
activeGames[gameID] = new Game(gameID, "player1", "player2")
Here's my working code:
这是我的工作代码:
index.js
:
index.js:
const handler = require("./request-handler");
handler.initialize('game-1234');
handler.initialize('game-5678');
request-handler.js
:
request-handler.js:
var gameManager = require('./game-manager');
exports.initialize = function(gameID) {
gameManager.initialize(gameID);
}
game-manager.js
:
game-manager.js:
var activeGames = {};
class Game {
constructor(id, player1, player2) {
this.id = id;
this.player1 = player1;
this.player2 = player2;
}
}
exports.initialize = function(gameID) {
activeGames[gameID] = new Game(gameID, "player1", "player2");
console.log(`game initialized! ${ Object.keys(activeGames).length } active games`);
}
Running node index
results in this:
运行的节点索引会导致以下结果:
game initialized! 1 active games
game initialized! 2 active games
#3
1
When you require a script file in Node.js, it is compiled as part of a function called with named parameters require
, module
, exports
and other exposed variables as arguments1. Variables declared at file level within the required script become function level variables in the enclosing module wrapper and retained inside its closure.
当您需要节点中的脚本文件时。它作为函数的一部分进行编译,函数的命名参数require、模块、导出和其他公开的变量arguments1。在所需脚本的文件级声明的变量在封装模块包装器中成为函数级变量,并保留在其闭包中。
Hence your "global variable" is no such thing: it's a variable defined inside a closure...
因此,您的“全局变量”不是这样的:它是在闭包中定义的变量……
An important question then is does the module loader make variables declared in a parent module available to scripts required inside the parent. A quick test shows that the answer is general: no, modules do not have automatic access to variables declared in other modules - those variables are inside closures.
一个重要的问题是,模块装入器是否使父模块中声明的变量对父模块中所需的脚本可用。快速测试表明,答案是一般的:不,模块没有自动访问在其他模块中声明的变量——这些变量在闭包中。
This indicates that to pass variable values to scripts that have been required, generally pass them as argument values to exported functions.
这表明要将变量值传递给已经需要的脚本,通常要将它们作为参数值传递给导出的函数。
It is also possible to export any javascript value as a property of module.exports
from within a required script, or add properties to an exports
object after it has been returned from requiring a script. Hence it is technically feasible to pass information up and down between modules by adding properties to exports
objects.
也可以将任何javascript值作为模块的属性导出。从所需的脚本中导出,或者在导出对象从需要脚本返回后向该对象添加属性。因此,通过向导出对象添加属性在模块之间传递信息在技术上是可行的。
Redesigned code has multiple options to
重新设计的代码有多种选择
-
define
activeGames
at the application level and pass it down as a parameter to modules needing access to it, or在应用程序级别定义activeGames,并将其作为参数传递给需要访问它的模块,或者
-
export
activeGames
fromgame-manager.js
by adding出口从game-manager activeGames。js通过添加
exports.activeGames = activeGames
to the end of the file. This will not take care of exporting
activeGames
out of the parent modulerequest-manager.js
for use elsewhere, but it could be a start. Or直到文件的末尾。这将不考虑从父模块request-manager导出activeGames。可以在其他地方使用js,但这可能是一个开始。或
-
define
activeGames
as a global variable (in node) using将activeGames定义为一个全局变量(在节点中)
global.activeGames = {} // define a global object
Defining global variables is not encouraged as it can lead to collisions (and consequent program failure) between names used by applications, code libraries, future library updates and future versions of ECMAScript. Or,
不鼓励定义全局变量,因为它可能导致应用程序、代码库、未来库更新和未来版本的ECMAScript之间名称之间的冲突(以及随后的程序失败)。或者,
-
Define an application namespace object for data global to the application. Require it wherever access to application data is needed:
为应用程序定义数据全局的应用程序命名空间对象。要求它在任何需要访问应用程序数据的地方:
-
create
appdata.js
as an empty file. Optionally include a comment:创建appdata。js作为一个空文件。包括一个注释(可选):
// this files exports module.exports without modification
-
require
appdata.js
wherever needed.需要appdata。任何需要的js。
var appData = require('./appdata.js') appData.gameData = {}; // for example
This relies on node.js maintaining a cache of previously required modules and does not recompile modules simply because they have been required a second time. Instead it returns the
exports
object of the previousrequire
.这依赖于节点。js维护以前需要的模块的缓存,不重新编译模块,仅仅是因为它们需要第二次编译。相反,它返回先前需要的export对象。
-
Happy festive season.
快乐的节日期间。
References
1The Node.js Way - How
require()
Actually Works
#1
1
JavaScript has lexical scope, not dynamic scope. ref: https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scoping
JavaScript有词法范围,而不是动态范围。裁判:https://en.wikipedia.org/wiki/Scope_(computer_science)# Lexical_scoping
Lexical scope means that whether a variable is accessible or not depends on where they appear in the source text, it doesn't depend on runtime information.
词法作用域意味着变量是否可访问取决于它们在源文本中的位置,它不依赖于运行时信息。
example:
例子:
function foo() {
var bar = 42;
baz();
}
function baz() {
console.log(bar); // error because bar is not in the scope of baz
}
the same problem happens in your code,
同样的问题也发生在你的代码中,
var activeGames
var activeGames
is not in scope.
不在范围内。
try this variation:
试试这种变化:
exports.initialize = function(){
var activeGames = {}
var gameID = "game12345"
activeGames.gameID = new Game(gameID, "player1", "player2")
}
A good solution could be to use a class and export it: --THIS CODE IS NOT TESTED--
一个好的解决方案可能是使用一个类并将其导出:—此代码没有经过测试—
class gamesManager {
var activeGames = {}
initialize() {
var gameID = "game12345"
activeGames.gameID = new Game(gameID, "player1", "player2")
}
}
exports.gamesManager = gamesManager
USE:
使用:
const activeGames = require('./game-manager');
const activeGamesInstance = new activeGames.gamesManager();
activeGamesInstance.initialize();
#2
1
Need a code sample for this one. I ran this locally and it worked fine, although your code has a big issue which may be a part of your problem. It looks like you want to keep track of multiple games in activeGames
. You need to use this syntax instead:
为此需要一个代码示例。我在本地运行这个程序,它运行得很好,尽管您的代码有一个很大的问题,这可能是问题的一部分。看起来你想在活动游戏中跟踪多个游戏。你需要使用这种语法来代替:
activeGames[gameID] = new Game(gameID, "player1", "player2")
Here's my working code:
这是我的工作代码:
index.js
:
index.js:
const handler = require("./request-handler");
handler.initialize('game-1234');
handler.initialize('game-5678');
request-handler.js
:
request-handler.js:
var gameManager = require('./game-manager');
exports.initialize = function(gameID) {
gameManager.initialize(gameID);
}
game-manager.js
:
game-manager.js:
var activeGames = {};
class Game {
constructor(id, player1, player2) {
this.id = id;
this.player1 = player1;
this.player2 = player2;
}
}
exports.initialize = function(gameID) {
activeGames[gameID] = new Game(gameID, "player1", "player2");
console.log(`game initialized! ${ Object.keys(activeGames).length } active games`);
}
Running node index
results in this:
运行的节点索引会导致以下结果:
game initialized! 1 active games
game initialized! 2 active games
#3
1
When you require a script file in Node.js, it is compiled as part of a function called with named parameters require
, module
, exports
and other exposed variables as arguments1. Variables declared at file level within the required script become function level variables in the enclosing module wrapper and retained inside its closure.
当您需要节点中的脚本文件时。它作为函数的一部分进行编译,函数的命名参数require、模块、导出和其他公开的变量arguments1。在所需脚本的文件级声明的变量在封装模块包装器中成为函数级变量,并保留在其闭包中。
Hence your "global variable" is no such thing: it's a variable defined inside a closure...
因此,您的“全局变量”不是这样的:它是在闭包中定义的变量……
An important question then is does the module loader make variables declared in a parent module available to scripts required inside the parent. A quick test shows that the answer is general: no, modules do not have automatic access to variables declared in other modules - those variables are inside closures.
一个重要的问题是,模块装入器是否使父模块中声明的变量对父模块中所需的脚本可用。快速测试表明,答案是一般的:不,模块没有自动访问在其他模块中声明的变量——这些变量在闭包中。
This indicates that to pass variable values to scripts that have been required, generally pass them as argument values to exported functions.
这表明要将变量值传递给已经需要的脚本,通常要将它们作为参数值传递给导出的函数。
It is also possible to export any javascript value as a property of module.exports
from within a required script, or add properties to an exports
object after it has been returned from requiring a script. Hence it is technically feasible to pass information up and down between modules by adding properties to exports
objects.
也可以将任何javascript值作为模块的属性导出。从所需的脚本中导出,或者在导出对象从需要脚本返回后向该对象添加属性。因此,通过向导出对象添加属性在模块之间传递信息在技术上是可行的。
Redesigned code has multiple options to
重新设计的代码有多种选择
-
define
activeGames
at the application level and pass it down as a parameter to modules needing access to it, or在应用程序级别定义activeGames,并将其作为参数传递给需要访问它的模块,或者
-
export
activeGames
fromgame-manager.js
by adding出口从game-manager activeGames。js通过添加
exports.activeGames = activeGames
to the end of the file. This will not take care of exporting
activeGames
out of the parent modulerequest-manager.js
for use elsewhere, but it could be a start. Or直到文件的末尾。这将不考虑从父模块request-manager导出activeGames。可以在其他地方使用js,但这可能是一个开始。或
-
define
activeGames
as a global variable (in node) using将activeGames定义为一个全局变量(在节点中)
global.activeGames = {} // define a global object
Defining global variables is not encouraged as it can lead to collisions (and consequent program failure) between names used by applications, code libraries, future library updates and future versions of ECMAScript. Or,
不鼓励定义全局变量,因为它可能导致应用程序、代码库、未来库更新和未来版本的ECMAScript之间名称之间的冲突(以及随后的程序失败)。或者,
-
Define an application namespace object for data global to the application. Require it wherever access to application data is needed:
为应用程序定义数据全局的应用程序命名空间对象。要求它在任何需要访问应用程序数据的地方:
-
create
appdata.js
as an empty file. Optionally include a comment:创建appdata。js作为一个空文件。包括一个注释(可选):
// this files exports module.exports without modification
-
require
appdata.js
wherever needed.需要appdata。任何需要的js。
var appData = require('./appdata.js') appData.gameData = {}; // for example
This relies on node.js maintaining a cache of previously required modules and does not recompile modules simply because they have been required a second time. Instead it returns the
exports
object of the previousrequire
.这依赖于节点。js维护以前需要的模块的缓存,不重新编译模块,仅仅是因为它们需要第二次编译。相反,它返回先前需要的export对象。
-
Happy festive season.
快乐的节日期间。
References
1The Node.js Way - How
require()
Actually Works