【问题标题】:socket undefined inside of socket.onsocket.on 内部未定义的套接字
【发布时间】:2018-04-29 10:38:56
【问题描述】:

我有当前代码;

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){ /*...*/ });

这是我正在使用的两个 on 方法; 在第一个区块中,您可以看到我正在做同样的事情,但它确实有效..

另外请注意,使用 socket.id 对用户进行身份验证有多安全?是否可以强制设置自己的id?

【问题讨论】:

  • 请不要将代码发布为图像。将代码作为文本发布,然后我们可以复制/粘贴以向您显示对代码的更正,而无需手动重新输入内容。另外,您也永远无法从图像搜索索引中受益。

标签: javascript node.js socket.io


【解决方案1】:

您是在循环中使用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(...)

一般来说,在for 循环中使用var 定义变量是一种不好的做法。它导致了“假设”,即它仅适用于该循环,但实际上,它适用于整个函数,并且可能会与循环之外的事物发生冲突。

在 ES6 中,您可以使用 letconst 而不是 var 来声明一个实际上只作用于循环块的变量。

另外请注意,您永远不应该使用for/in 迭代数组。这会迭代所有数组属性(包括其他可枚举对象属性),而不仅仅是数组元素。 ES6 添加了for/of 用于以这种方式迭代数组。在 ES5 中,您可以使用更传统的 for 循环或 .forEach()

【讨论】:

  • @bloodless2010 - 如果我可以复制/粘贴部分代码,我会在答案中包含更多您的代码,但在图像中发布代码是这样做的一大障碍。
  • 哇!我不敢相信我错过了我完全不知道 JavaScript 以这种方式工作,在我使用其他语言的实践中,我认为它只在循环范围内。明白了这么多,谢谢!
猜你喜欢
  • 2015-04-15
  • 2019-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-10
  • 2020-07-09
  • 1970-01-01
  • 2013-04-25
相关资源
最近更新 更多