【问题标题】:Javascript closures - behavior of overridden functions from the global scopeJavascript 闭包 - 全局范围内被覆盖函数的行为
【发布时间】:2012-03-09 10:44:30
【问题描述】:

这个问题更多是关于javascript原理的。

function done(){ console.log('done defined with `function done(){ ...`'); }
var done = function(){ console.log('done defined with `var done = ...`'); }
done = function(){ console.log('without `var`, just `done = ...`'); }

如果在<script> 标签内定义,它们都会做同样的事情,对吗?

但是如果我将它们放在一个闭包中 (function(){ 函数定义在这里 }()) 这三种类型中的任何一种都会覆盖全局定义的函数 done()或在各自的闭包中定义的任何其他 done() 函数?

如果上面的问题没有意义,那就换个说法;

  • 以下代码是否应该在任何 JS 运行时中执行相同的操作?
  • eval-ing 代码在上下文或全局范围内执行特定代码?
  • 如何配置setTimeout 调用,以便其“引号”之间的代码在调用特定setTimeout 的范围内执行(请参阅下面for 内的第二个超时)?我的意思是除了定义window.blabla函数并告诉它们运行后删除自己之外还有其他方法吗?

    function done(d){ console.log('cha cha cha: '+d); }
    setTimeout( function(){ done(2); }, 3500 );
    
    for(i=0; i<10; i++){
        (function(){
            done = function(x){ console.log('done #'+i+' sais: '+x); }
            setTimeout(function(){ done(i*2); },2500);
            setTimeout(function(){ done(i*2); }.toString()+'(); ',2500);
        }());
    }
    

【问题讨论】:

  • 不要使用第二种超时方法。还是有什么原因?

标签: javascript scope closures


【解决方案1】:

关于一般行为的初始问题:

  • var done =function done 基本上做同样的事情。它们将在内部范围内隐藏外部定义,但不会在外部范围内替换它。

  • done = 将在作用域内设置相应的done 变量,如果这样的变量不存在且程序未在严格模式下运行,则将创建一个全局变量。

  • 1234563 - 反正更好)。

至于非常邪恶的 setTimeout 和 eval 问题:

  • 是的,我想这种东西应该足够标准化,可以在任何地方都一样工作。无论如何,我仍然会测试它。 (或者你可以使用不同的解决方案,因为 eval 是多么邪恶)

  • eval 在当前范围内运行代码(使用深黑魔法)。如果您想在全局范围内运行代码,您可以改用new Function

  • 为了让 settimeout 在当前范围内运行字符串,您可以自己添加 eval

    var done = function(d){ console.log('outer done', d); };
    
    (function(){
        var done = function(x){ console.log('inner done', x); };
    
        setTimeout(function(){ done(1); }, 200);           //inner done
        setTimeout('done(2)', 400);                        //outer done
        setTimeout(function(){ eval('done(3)'); }, 600);   //inner done
    }());
    
  • 再一次,您为什么要评估 setTimeouts 中的内容?这一切听起来都非常邪恶!

【讨论】:

  • 最完整的答案,谢谢。这不是邪恶的,虽然我正在用悍马穿越猴子,告诉猴子从悍马内部做一些事情,为了将我所有的代码保留在同一个 JS 项目中,我不得不做一些疯狂的事情,比如传递函数通过 JSON。这也是语法高亮的问题。
  • 好吧,在这里我住的地方骑着悍马穿越猴子被认为是邪恶的:P
  • 对于带有 eval 的 setTimeout,您不需要 eval,您只需将 eval 中的函数绑定到 this 范围内即可。
  • @helly0d:我知道,这就是我在第一个示例中所做的。 settimeout里面的eval是和传一个字符串给settimeout的case比较。
【解决方案2】:

关于您的第一个块的注释。当您在第一行中为函数命名时,该函数名称在编译时被解析并且在作用域内的任何地方都可用。如果您只是将一个函数分配给一个变量,那么该函数(即变量)仅在运行时定义之后才可用,甚至如果您给它一个名称。

例如:

// this is valid
foo();
function foo(){ console.log("foo"); }

// this throws an error...
bar();
var bar = function (){ console.log("bar"); };

// ...and so does this...
baz();
var bat = function baz(){ console.log("bazbat"); };

// ...and this!
baz();

【讨论】:

    【解决方案3】:

    var donedone之间存在差异,因为后者隐含window.done,因此可以是deleted。

    语句done = foobar; 将覆盖作用域链中的下一个“done”变量。如果有一个本地的var,它会改变,如果有一个全局的,它会覆盖那个,如果没有,它会创建一个新的全局。 所有这些都不会影响其他作用域(闭包)中的任何私有变量。

    【讨论】:

      猜你喜欢
      • 2017-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-19
      相关资源
      最近更新 更多