6

考虑代码:

    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. 

基本上我已经尝试了所有可能的方法,但似乎都没有完成这项工作。有人可以解释为什么吗?

4

2 回答 2

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 ) 不是参考。
    a) 让thisValue未定义。
  8. 返回在func上调用 [[Call]] 内部方法的结果,提供thisValue作为 this 值,并提供列表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);

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

于 2012-03-30T11:08:10.053 回答
1

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

于 2012-03-30T11:08:25.073 回答