Почему Javascript не позволяет функции переопределять себя изнутри себя? - PullRequest
5 голосов
/ 30 марта 2012

Рассмотрим код:

    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 ]

8 голосов
/ 30 марта 2012

Вы успешно переопределяете функцию, просто вызывающее выражение уже захватило ссылку на старую функцию: первое, что происходит в выражении вызова, - это то, что определяется функцией, вызывающей функциюоценивается, см. Раздел 11.2.3 спецификации:

11.2.3 Вызовы функций

Производство Выражение CallExpression:Аргументы MemberExpression оцениваются следующим образом:

  1. Пусть ref будет результатом вычисления MemberExpression .
  2. Let func be GetValue ( ref ).
  3. Пусть argList будет результатом вычисления Аргументы , создавая внутренний список значений аргументов(см. 11.2.4).
  4. Если тип ( func ) не является объектом, генерировать исключение TypeError.
  5. If IsCallable ( func )false, выдает исключение TypeError.
  6. Если тип ( ref ) равен Reference, тогда
    a) Если IsPropertyReference ( ref ) имеет значение true, тогда
    i.Пусть thisValue будет GetBase ( ref ).
    b) Иначе, основа ref является рекордом окружающей среды
    i.Пусть thisValue будет результатом вызова конкретного метода ImplicitThisValue GetBase ( ref ).
  7. Иначе, Тип ( ref ) не является ссылкой,
    a) Пусть thisValue не определено.
  8. Возвращает результат вызова внутреннего метода [[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).

1 голос
/ 30 марта 2012

JavaScript имеет строгое правило слева направо для порядка вычисления аргументов оператора. Я предполагаю, что это включает в себя оператор вызова функции, что означает, что первый a вычисляется перед выражением.

...