我有当前的代码;
socket.on('KeyPress', function(data){
var ply = PLAYER_LIST[socket.id];
/* ... */
});
WebStorm告诉我socket.id可能没有被初始化,然后当这个事件被触发时它确实会导致错误
TypeError: Cannot read property 'id' of undefined
整个代码在
之内io.sockets.on('connection', function(socket){ /*...*/ });
以下是我使用的方法中的两个; 在第一个区块中,您可以看到我做同样的事情但它有效..
另外在那个注意事项中使用socket.id来授权用户有多安全?是否可以强制设置自己的ID?
答案 0 :(得分:2)
你是在循环中用var
定义变量的不良做法的受害者,然后在“变量提升”的影响下得到一点,其中在函数的任何地方用var
定义的变量是在函数开始时自动声明,然后初始化你的赋值所在的位置,这意味着在此之前函数中的undefined
无处不在。
问题在于这行代码:
var socket = SOCKET_LIST[i];
这就是重新定义一个名为socket
的局部变量,它隐藏了你真正想要的变量。使用var
定义的变量是函数作用域。这意味着它们被定义在函数的顶部(这称为变量提升),因此隐藏了另一个父范围的socket
变量。
将您的功能视为如下所示:
socket.on('KeyPress', function(data) {
var socket; // this is hoisted from deeper inside the function
// and creates a new undefined socket variable
var ply = PLAYER_LIST[socket.id];
// other code here
});
这基本上是Javascript看到你代码的方式。您可以搜索“Javascript变量提升”,如果您想了解更多信息,请参阅有关该主题的大量文章。
您可以将此局部变量的名称更改为其他内容的最小更改不会干扰父作用域变量,但实际上这个代码结构首先并不理想。
var localSocket = SOCKET_LIST[i];
var ply = PLAYER_LIST[p];
localSocket.emit(...)
通常,在var
循环内定义带for
的变量是一种不好的做法。它导致了“假设”它仅限于该循环,但实际上,它的范围是整个函数,并且可以搞乱循环之外的东西。
在ES6中,您可以使用let
或const
代替var
来声明一个实际范围仅限于循环块的变量。
另外请注意,您永远不应该使用for/in
迭代数组。它迭代所有数组属性(包括其他可枚举对象属性),而不仅仅是数组元素。 ES6以这种方式为迭代数组添加for/of
。在ES5中,您可以使用更传统的for
循环或.forEach()
。