代码之家  ›  专栏  ›  技术社区  ›  Brent Aureli

回调函数缺少所需数据的作用域

  •  2
  • Brent Aureli  · 技术社区  · 7 年前

    我有一个回调函数的变量丢失其作用域的问题

    。 我在一个数组中有以下两个对象(简化以显示问题)

    const search = [{socket: new WebSocket('ws://live.trade/123')}, 
                    {socket: new WebSocket('ws://live.trade/xyz')}];
    

    然后,我对它们进行forEach,试图在套接字打开后记录套接字url。

    search.forEach(function(element){
        element.socket.on('open', function open() {
          console.log(element.socket.url);
        });
    });
    
    *actual output*
    ws://live.trade/xyz
    ws://live.trade/xyz
    
    *expected*
    ws://live.trade/123
    ws://live.trade/xyz
    

    我觉得原因是,当函数open()运行时,元素不在作用域中,它只使用上一个元素(ws://live.trade/xyz)。 这是正确的吗?最后,解决这个问题的方法是什么?它的真正用途是当套接字打开时,我需要通过调用它的套接字将版本数据发送到服务器。。。现实中我会有很多套接字,不想写“socket.on('open'…)”对于每个单独的一个。

    有什么建议吗?

    非常感谢!

    1 回复  |  直到 7 年前
        1
  •  1
  •   xdrm-brackets    7 年前

    您的回拨( i、 e.插座中。on() )使用 element 的变量 forEach() .从您的实际结果来看,这可能意味着:

    1、范围问题

    变量可以是“ 被覆写 “在迭代过程中,由于javascript/节点作用域机制,您给出的代码并非如此,但在循环中使用作用域是一个常见问题。

    在这种情况下,您必须执行以下操作:

    search.forEach(function(element){
        element.socket.on('open', function(){
          console.log(this.socket.url);
        }.bind(element));
    });
    

    说明:

    • bind() 传递其第一个参数( 要素 在本例中为变量)转换为匿名函数 this 在里面。
    • 在回调函数中, this.socket 相当于 element.socket 在适当的迭代中

    [更新] 在指出之后 Felix Kling ,forEach()为每个元素提供一个作用域。

    看见 bind 了解更多详细信息。

    2、依赖性问题

    如果不是范围问题,则可能意味着您使用的库无法按预期工作。也许,试着记录 要素 在forEach()中检查 WebSocket 对象是您所期望的。

    编辑

    • 有关节点/js循环和参考的更多信息,请参阅 here
    • 对于一般的节点/js闭包:请参见 here