函数外的未定义变量

Undefined variable outside of a function

我有一个使用 node.js 和 socket.io 的代码。

当我这样写这段代码时;

服务器端:

function display(width, height){
  this.width = width * 2;
  this.height = height * 2;
}

function position(x, y){
  this.x = x;
  this.y = y;
}

function initialize(){
  for(var x = circlePosition.length; x < circleCount; x++){
    circlePosition[x] = new position(Math.random() * (resolution.width - (-resolution.width)) + (-resolution.width), Math.random() * (resolution.height - (-resolution.height)) + (-resolution.height));
    
  }
}

socket.on('display',
      function(data) {
        resolution = new display(data.width, data.height);
        initialize();
        io.sockets.emit('positioning', circlePosition);
      });

客户端;

var position;
var resolution = {
  width: 1366,
  height: 666
 };

 socket.emit('display', resolution);

 socket.on('positioning',
  function(data){
   position = data;
  });
 console.log(position); // <---

位置变量未定义,但如果我在客户端使用此代码

var position;
var resolution = {
  width: 1366,
  height: 666
 };

 socket.emit('display', resolution);

 socket.on('positioning',
  function(data){
   position = data;
      console.log(position); // <---
  });
 

它有价值。为什么我不能在函数外使用使用 socket.io 发送的值?

在第一个客户端场景中,您的 console.log(position) 在您的事件处理程序具有 运行 之前 运行。请记住,当您执行 socket.on(...) 时,您只是在注册一个可能在将来某个时间调用的事件处理程序。您的其余代码继续 运行。因此,注册事件处理程序后的下一行是 console.log() 语句。由于事件处理程序尚未被触发(已注册,但尚未发生任何事件使其 运行),position 还没有值。

因此,查看您的代码:

socket.on('positioning', function(data) {
    position = data;
});
// position has not yet been set because the above event handler
// has not yet been triggered
console.log(position);

使用 positioning 事件发送的数据的唯一安全位置是在回调内部,这正是您在其他情况下正常工作的情况:

socket.on('positioning', function(data) {
    // use the data here
    console.log(data);
});

仅供参考,这是事件驱动编程的基本概念。您注册在将来某个时间调用的事件处理程序。您通常不知道它们何时会被调用,因此您必须只处理它们在被调用时在事件处理程序中提供的数据。

socket.on() 是一个异步调用——这意味着您只会在 data 从服务器完全加载后调用匿名函数


注意:您可以使用匿名函数之后匿名函数的另一个代码中的position 运行(是的,您需要等待才能访问它)。但是怎么办?那么,最好的方法是将相关代码放入其自己的函数中,然后从回调函数中调用该函数,如本例所示:

var position;
var resolution = {
  width: 1366,
  height: 666
};

socket.emit('display', resolution);

socket.on('positioning',
  function(data) {
    loadPosition(); // <---
  }
);

function loadPosition() {
  position = data;
  console.log(position); // ... do whatever you need to do with postion here
}

你可以通过你object/value收到的回调响应

var position;
var resolution = {
    width: 1366,
    height: 666
};

socket.emit('display', resolution);

socket.on('positioning',
    function(data){
        position = data;
    positionUpdate()
    });

function positionUpdate(){
console.log(position); 
}

想想这行代码到底在做什么:

socket.on('positioning',
   function(data){
      position = data;
   });

这是在设置一个 回调函数,当您收到 positioning 事件时将调用该回调函数。但是请注意,这个函数还没有被调用!它将在将来的某个时候被调用。这只是函数的初始化

如果你在回调函数初始化之后调用,那console.log()会在[=35之前] =] 该函数实际上被调用了!这就是变量未定义的原因,因为变量还没有被设置!

如果您将 console.log() 调用 放在 回调函数中,那么您可以保证它在 之后发生回调函数被调用,所以变量被设置。

如果不使用内联函数可能会更清楚:

var position;
var resolution = {
        width: 1366,
        height: 666
    };

socket.emit('display', resolution);
socket.on('positioning', myCallback);
console.log(position);

function myCallback(data){
   position = data;
}

这正是您的代码所做的,只是现在我使用的是命名函数而不是内联函数。但是现在更明显的是console.log()执行的时候回调还没有被调用。

如果您还没有解决问题,请试试这个。这就是我所做的。

var resolution = {
    width: 1366,
    height: 666
};

socket.emit('display', resolution);

socket.on('positioning', function(data){
    getPosition(data, position);
});

var getPosition = function(data, callback){
   callback(data);
}

var position = function(data){
   console.log(data); // <--
}