Вы успешно переопределяете функцию, просто вызывающее выражение уже захватило ссылку на старую функцию: первое, что происходит в выражении вызова, - это то, что определяется функцией, вызывающей функциюоценивается, см. Раздел 11.2.3 спецификации:
11.2.3 Вызовы функций
Производство Выражение CallExpression:Аргументы MemberExpression оцениваются следующим образом:
- Пусть ref будет результатом вычисления MemberExpression .
- Let func be GetValue ( ref ).
- Пусть argList будет результатом вычисления Аргументы , создавая внутренний список значений аргументов(см. 11.2.4).
- Если тип ( func ) не является объектом, генерировать исключение TypeError.
- If IsCallable ( func )false, выдает исключение TypeError.
- Если тип ( ref ) равен Reference, тогда
a) Если IsPropertyReference ( ref ) имеет значение true, тогда
i.Пусть thisValue будет GetBase ( ref ).
b) Иначе, основа ref является рекордом окружающей среды
i.Пусть thisValue будет результатом вызова конкретного метода ImplicitThisValue GetBase ( ref ). - Иначе, Тип ( ref ) не является ссылкой,
a) Пусть thisValue не определено. - Возвращает результат вызова внутреннего метода [[Call]] для func , обеспечивая thisValue в качестве значения this и предоставление списка argList в качестве значений аргумента.
Шаги 1 и 2 выполняются до переопределения функции.
Решение, конечно, состоит в том, чтобы все происходило в ожидаемом порядке ( живой пример | 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);
Примечание: этоИнтересно, что ваш первый пример работает в Chrome (V8) (он также работает в версии JScript для IE6; но в JScript было много проблем).Это не должно работать, и не работает в Firefox (SpiderMonkey), Opera (Carakan) или IE9 (Chakra).