为什么Javascript不让一个函数从内部重新定义自己?

时间:2012-03-30 11:04:19

标签: javascript scope definition redefinition

考虑代码:

    window.a = function(x){ 
        var r = x*2; 
        window.a =alert; // redefines itself after first call
        return r;
    }; 
    a('2 * 2 = '+a(2)); // doesn't work. it should've alerted "2 * 2 = 4"

这也不起作用:

    window.a = function(x){ 
        alert(x); 
        window.a = function(x){ // redefines itself after first call
            var r = x*2; 
            return r;   
        }
    }; 
    a('2 * 2 = '+a(2)); // doesn't work. it should've alerted "2 * 2 = 4"

这两者都没有:

    window.a = function(x){ alert(x); window.c = window.a; window.a = window.b; window.b = window.c; };
    window.b = function(x){ var r = x*2; window.c = window.b; window.b = window.a; window.a = window.c; return r; };
    a('2 * 2 = '+a(2)); // doesn't work. 

基本上我已经尝试了所有可能的方法,似乎都没有做到这一点。有人可以解释一下原因吗?

2 个答案:

答案 0 :(得分:8)

您的成功重新定义的功能,它只是表达调用它已经抓住了老函数的引用:这种情况发生在通话中表达的第一件事是,东西定义调用什么功能评估,请参阅规范的Section 11.2.3

  

11.2.3函数调用

     

生产 CallExpression:MemberExpression Arguments 的计算方法如下:

     
      
  1. ref 成为评估 MemberExpression 的结果。
  2.   
  3. func 为GetValue( ref )。
  4.   
  5. argList 成为评估 Arguments 的结果,生成一个参数值的内部列表(见11.2.4)。
  6.   
  7. 如果Type( func )不是Object,则抛出TypeError异常。
  8.   
  9. 如果IsCallable( func )为false,则抛出TypeError异常。
  10.   
  11. 如果Type( ref )是Reference,那么   
    a)如果IsPropertyReference( ref )为真,那么   
    我。让 thisValue 为GetBase( ref )。   
    b)否则, ref 的基础是环境记录   
    我。让 thisValue 成为调用GetBase的ImplicitThisValue具体方法的结果( ref )。
  12.   
  13. 否则,Type( ref )不是Reference。   
    a)让 thisValue 未定义。
  14.   
  15. 返回调用的结果[[调用]]上的 FUNC 内部的方法,提供的 thisValue 作为该值,并提供所述列表 ARGLIST 作为参数值。
  16.   

步骤1和2发生在重新定义函数之前。

解决方案当然是按照您期望的顺序(live example | source)来实现:

window.a = function(x){ 
    var r = x*2; 
    window.a =alert; // redefines itself after first call
    return r;
}; 
var val = a(2);
a('2 * 2 = '+ val);

旁注:有趣的是your first example在Chrome(V8)中有效(它也适用于IE6的JScript版本;但是,JScript有很多的问题)。它应该不起作用,并且不适用于Firefox(SpiderMonkey),Opera(Carakan)或IE9(Chakra)。

答案 1 :(得分:1)

JavaScript对运算符参数的评估顺序有严格的从左到右的规则。我猜这包括函数调用操作符,这意味着在表达式之前评估第一个a