【问题标题】:Scope of variable inside callbacks回调中的变量范围
【发布时间】:2016-03-09 12:51:05
【问题描述】:
var net = require('net');
net.createServer(function(socket){
    console.log('CONNECTED: ' + socket.remoteAddress +':'+ socket.remotePort);
    var id = '123';
    socket.on('data',function(data){
        console.log(id);
        setTimeout(function(){
            console.log(id);
        },5000);
    });
}).listen(10000,'');

在这段代码中它应该打印 123 和未定义,对吗?但它会打印 123 和 123。根据我的理解 setTimeout 在某个时间后执行,在那个时间点它无法访问 id 变量。我真的很困惑。为什么会发生这种情况,我哪里错了。

【问题讨论】:

    标签: javascript node.js scope


    【解决方案1】:

    socket.on 和 setTimeout 的回调都在定义 id 变量的范围内。由于两个回调都没有定义自己的本地id,所以它们都打印 123。

    【讨论】:

    • 所以无论回调何时执行,它都可以访问其父范围的变量?
    • @user3508612 - 没错。这称为closure,它是 JavaScript 中一个非常重要的概念。
    【解决方案2】:

    在这段代码中它应该打印 123 和未定义,对吗?但它打印 123 和 123。

    那是因为setTimeout 函数没有本地 id 变量。

    以下将打印您要查找的输出

     setTimeout(function(){  
            var id;
            console.log(id);
        },5000);
    

    这是因为即使setTimeout的函数也有自己的作用域,如果变量没有在内部函数中定义,它会使用外部函数的作用域。

    【讨论】:

      【解决方案3】:

      注意:这个 polyfill 只运行浏览器。如果您在 nodejs 中使用此代码,您会在某处更改..

      /*  setTimeout argument supports    */
      if (document.all && !window.setTimeout.isPolyfill) {
          var __nativeST__ = window.setTimeout;
          window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
              var aArgs = Array.prototype.slice.call(arguments, 2);
              return __nativeST__(vCallback instanceof Function ? function () {
                  vCallback.apply(null, aArgs);
              } : vCallback, nDelay);
          };
          window.setTimeout.isPolyfill = true;
      }
      
      if (document.all && !window.setInterval.isPolyfill) {
          var __nativeSI__ = window.setInterval;
          window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
              var aArgs = Array.prototype.slice.call(arguments, 2);
              return __nativeSI__(vCallback instanceof Function ? function () {
                  vCallback.apply(null, aArgs);
              } : vCallback, nDelay);
          };
          window.setInterval.isPolyfill = true;
      }
      

      例子:

      setTimeout(function(id){
                  console.log(id);
              },5000,"hello");
      

      //5 秒然后 //你好;

      详细信息this

      更改代码:

      var net = require('net');
      net.createServer(function(socket){
          console.log('CONNECTED: ' + socket.remoteAddress +':'+ socket.remotePort);
          var id = '123';
          socket.on('data',function(data){
              console.log(id);
              setTimeout(function(id){
                  console.log(id);
              },5000, id);
          });
      }).listen(10000,'');
      

      【讨论】:

        猜你喜欢
        • 2015-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-18
        • 2014-10-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多