Javascript全局变量在函数范围内未定义

时间:2017-12-23 23:49:11

标签: javascript node.js

我是JavaScript新手并尝试创建一个简单的节点服务器。这是我的代码:

ArrayList<String> languages=new ArrayList<String>();
ArrayList<Person> Persons=new ArrayList<Person>();

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);
        .
        .
        .
        .
        .
        .
                english=(CheckBox)findViewById(R.id.english);
                if(anglais.isChecked())
                    languages.add(english.getText().toString());
                Persons.add(new Person(languages));
                Log.i("test: ",Persons.get(0).getLangues().get(0)); // Will show English
                languages.clear(); // Here I clear the languages ArrayList so I can add new languages for another person
                Log.i("test: ",Persons.get(0).getLangues().get(0)); // Produces an exception.
            }
        });
    }

我从另一个模块调用initialize函数,我收到一条错误,指出activeGames未定义。 activeGames位于文件的最外层。我尝试添加&#39;这个&#39;在activeGames.gameID之前,但没有修复它。为什么activeGames未定义?提前谢谢。

编辑:这是我如何调用此代码。

在我的基本索引文件中我有

var activeGames = {}

exports.initialize = function(){
    var gameID = "game12345"
    activeGames.gameID = new Game(gameID, "player1", "player2")
}

在request-handler.js中,我有

const handler = require("./request-handler.js")
handler.initialize()

3 个答案:

答案 0 :(得分:1)

JavaScript具有词法范围,而不是动态范围。 参考:https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scoping

词法范围意味着变量是否可访问取决于它们在源文本中的显示位置,它不依赖于运行时信息。

示例:

function foo() {
  var bar = 42;
  baz();
}

function baz() {
  console.log(bar); // error because bar is not in the scope of baz
}

代码中出现同样的问题,

  

var activeGames

不在范围内。

尝试这种变化:

exports.initialize = function(){
    var activeGames = {}
    var gameID = "game12345"
    activeGames.gameID = new Game(gameID, "player1", "player2")
}

一个好的解决方案可能是使用一个类并导出它: - 未对该代码进行测试 -

class gamesManager {
   var activeGames = {}

   initialize() {
      var gameID = "game12345"
      activeGames.gameID = new Game(gameID, "player1", "player2")
   }
}

exports.gamesManager = gamesManager

使用:

const activeGames = require('./game-manager');
const activeGamesInstance = new activeGames.gamesManager();
activeGamesInstance.initialize();

答案 1 :(得分:1)

需要这个代码示例。我在本地运行它并且它工作正常,虽然您的代码有一个很大的问题,可能是您的问题的一部分。您似乎希望在activeGames中跟踪多个游戏。您需要使用此语法:

activeGames[gameID] = new Game(gameID, "player1", "player2")

这是我的工作代码:

index.js

const handler = require("./request-handler");

handler.initialize('game-1234');
handler.initialize('game-5678');

request-handler.js

var gameManager = require('./game-manager');

exports.initialize = function(gameID) {
    gameManager.initialize(gameID);
}

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`);
}

运行node index会产生以下结果:

game initialized! 1 active games
game initialized! 2 active games

答案 2 :(得分:1)

当你在Node.js中需要一个脚本文件时,它被编译为一个函数的一部分,该函数使用命名参数requiremoduleexports和其他公开的变量作为参数< SUP> 1 。在所需脚本中在文件级别声明的变量将成为封闭模块包装器中的函数级变量,并保留在其闭包内。

因此,你的“全局变量”不是这样的:它是一个在闭包内定义的变量......

然后,一个重要的问题是模块加载器是否在父模块中声明的变量可用于父模块内所需的脚本。快速测试表明答案是通用的:不,模块不能自动访问在其他模块中声明的变量 - 这些变量在闭包内。

这表示要将变量值传递给已经需要的脚本,通常将它们作为参数值传递给导出的函数。

还可以从所需脚本中将任何javascript值导出为module.exports的属性,或者在从需要脚本返回后向exports对象添加属性。因此,通过向exports个对象添加属性,在模块之间上下传递信息在技术上是可行的。

重新设计的代码有多个选项

  1. 在应用程序级别定义activeGames并将其作为参数传递给需要访问它的模块,或者

  2. 通过添加

    activeGames导出game-manager.js
      exports.activeGames = activeGames
    

    到文件的末尾。这不会将activeGames导出父模块request-manager.js以便在其他地方使用,但它可能是一个开始。或

  3. 使用

    activeGames定义为全局变量(在节点中)
      global.activeGames = {}  // define a global object
    

    不鼓励定义全局变量,因为它可能导致应用程序使用的名称,代码库,未来库更新和ECMAScript的未来版本之间的冲突(以及随之而来的程序失败)。或者,

  4. 为应用程序的全局数据定义应用程序命名空间对象。在需要访问应用程序数据的任何地方都需要它:

    • appdata.js创建为空文件。 可选择包括评论:

       // this files exports module.exports without modification
      
    • 在需要的地方需要appdata.js

      var appData = require('./appdata.js')
      appData.gameData = {}; // for example
      

    这依赖于node.js维护先前所需模块的缓存,并且不会仅仅因为第二次需要它们而重新编译模块。而是返回先前exports的{​​{1}}对象。

  5. 节日快乐。

    <小时/> 参考
    1 The Node.js Way - How require() Actually Works