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

Sil*_*ian 5 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"
Run Code Online (Sandbox Code Playgroud)

这也不起作用:

    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"
Run Code Online (Sandbox Code Playgroud)

这两样都不是:

    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. 
Run Code Online (Sandbox Code Playgroud)

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

T.J*_*der 8

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

11.2.3函数调用

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

  1. ref成为评估MemberExpression的结果.
  2. func为GetValue(ref).
  3. argList是评估Arguments的结果,产生一个参数值的内部列表(见11.2.4).
  4. 如果Type(func)不是Object,则抛出TypeError异常.
  5. 如果IsCallable(func)为false,则抛出TypeError异常.
  6. 如果Type(ref)是Reference,那么
      a)如果IsPropertyReference(ref)为真,那么
          i.让thisValue为GetBase(ref).
      b)否则,ref的基础是环境记录
          i.让thisValue成为调用GetBase(ref)的ImplicitThisValue具体方法的结果.
  7. 否则,Type(ref)不是Reference.
    a)让thisValue不确定.
  8. 返回在func上调用[[Call]]内部方法的结果,提供thisValue作为此值并提供列表argList作为参数值.

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

解决方案当然是按照您期望的顺序进行操作(实例 | 源代码):

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);
Run Code Online (Sandbox Code Playgroud)

旁注:有趣的是,您的第一个示例适用于Chrome(V8)(它也适用于IE6的JScript版本;但是,JScript有很多问题).它应该不起作用,并且不适用于Firefox(SpiderMonkey),Opera(Carakan)或IE9(Chakra).