使用相同的名称声明variables导致socket io中的问题

我花了一段时间才弄清楚是什么问题,但我想知道为什么这样做。

使用这个代码,variables播放器,播放器和套接字将是未定义的,导致错误。

var player = Player(socket.id, socket); socket.on('joinHost', function(data) { var gameID = data; player.gameID=gameID; var game = GAME_LIST[gameID]; game.players[socket.id]=player; var players = game.players; for (var p in players){ var player = players[p]; var socket = player.socket; socket.emit('playerJoined'); } }); 

避免使用相同名称的variables的声明使所有工作正常。

 var player = Player(socket.id, socket); socket.on('joinHost', function(data) { var gameID = data; player.gameID=gameID; var game = GAME_LIST[gameID]; game.players[socket.id]=player; var tempPlayers = game.players; for (var p in tempPlayers){ var tempPlayer = tempPlayers[p]; var tempSocket = tempPlayer.socket; tempSocket.emit('playerJoined'); } }); 

有趣的部分是,当我运行第一个代码时,它表示player.gameID=gameID行中的玩家是未定义的,而如果我删除了player.gameID=gameID之后的代码,则玩家被定义。 基本上, player.gameID=gameID之后的代码导致玩家未定义。

那么,为什么会这样呢?

当你声明var player = players[p]; 它被声明为整个函数范围(for循环没有它自己的范围)。

在执行函数体之前,当前范围中的名称将在开始时被全部评估。

所以当function(data)时,即使在var gameID = data;之前,名称player也会在该范围内重写var gameID = data; 被执行。

一个最小的例子:

 > var x = 'foo'; > f = function() { console.log(x); var x = 'bar'; } > f() undefined 

JavaScript将variables的声明移动到它们定义的范围的顶部,并给它们一个未定义的初始值,但保持赋值。 这叫做吊装

您的代码相当于:

 var player = Player(socket.id, socket); socket.on('joinHost', function(data) { var gameID; // undefined var game; // undefined var players; // undefined var player; // undefined var socket; // undefined gameID = data; player.gameID=gameID; // can't set property 'gameID' of undefined game = GAME_LIST[gameID]; game.players[socket.id]=player; // is undefined since 'player' is undefined at this stage players = game.players; // undefined for (var p in players){ player = players[p]; socket = player.socket; socket.emit('playerJoined'); } });