Why Javascript doesn't let a function redefine

2019-06-21 12:26发布

Consider the code:

    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"

This doesn't work either:

    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"

As neither does this:

    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. 

And basically I've tried all possible ways and neither seem to do the job. Can someone please explain why?

2条回答
何必那么认真
2楼-- · 2019-06-21 13:18

You are successfully redefining the function, it's just that the expression calling it has already grabbed the old function reference: The first thing that happens in a call expression is that the thing defining what function to call is evaluated, see Section 11.2.3 of the specification:

11.2.3 Function Calls

The production CallExpression : MemberExpression Arguments is evaluated as follows:

  1. Let ref be the result of evaluating MemberExpression.
  2. Let func be GetValue(ref).
  3. Let argList be the result of evaluating Arguments, producing an internal list of argument values (see 11.2.4).
  4. If Type(func) is not Object, throw a TypeError exception.
  5. If IsCallable(func) is false, throw a TypeError exception.
  6. If Type(ref) is Reference, then
      a) If IsPropertyReference(ref) is true, then
          i. Let thisValue be GetBase(ref).
      b) Else, the base of ref is an Environment Record
          i. Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref).
  7. Else, Type(ref) is not Reference.
    a) Let thisValue be undefined.
  8. Return the result of calling the [[Call]] internal method on func, providing thisValue as the this value and providing the list argList as the argument values.

Steps 1 and 2 occur before the function is redefined.

The solution is of course to make things happen in the order you expect (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);

Side note: It's interesting that your first example works in Chrome (V8) (it also works in IE6's version of JScript; but then, JScript had lots of issues). It shouldn't work, and doesn't in Firefox (SpiderMonkey), Opera (Carakan), or IE9 (Chakra).

查看更多
祖国的老花朵
3楼-- · 2019-06-21 13:20

JavaScript has a strict left-to-right rule for order of evaluation of operator arguments. I am guessing that this includes the function-call operator, which means that the first a is evaluated before the expression.

查看更多
登录 后发表回答