определения функций не подняты

W.r.t Подъем определений fxn.

if (true) {
  function foo() {
    alert(1)
  }
} else {
  function foo() {
    alert(2)
  }
}
foo()

Хром, где-то 2-3 месяца назад - печатал 2. Сейчас печатает 1. Я что-то пропустил или консоль перестала подниматься на fxn!

DEMO — печатает 1. Я не знаю, где найти демонстрацию старой версии браузера. Вероятно, установка узла более старого движка v8? Текущая версия хрома - 49


person Vivek Chandra    schedule 18.11.2016    source источник
comment
Как выполняется второе определение foo()? Конечно, правда всегда верна...   -  person Jazcash    schedule 18.11.2016
comment
@Jazcash В этом вся прелесть подъема. Тот факт, что код внутри оператора else не выполняется, не означает, что определение функции не обрабатывается.   -  person krillgar    schedule 18.11.2016
comment
Этот код вызовет ошибки в строгом режиме. Такое определение функций в условных предложениях — плохая практика.   -  person Pointy    schedule 18.11.2016
comment
Я только что отдал бывшего за подъем. Просто бывший   -  person Vivek Chandra    schedule 18.11.2016
comment
Вау, вы правы, я только что протестировал Chrome 37 в Browserstack, и он действительно печатает 2. Я в недоумении, думаю, мне следует сделать больше домашней работы по JS!   -  person Jazcash    schedule 18.11.2016
comment
@Pointy Здесь не выбрасываются исключения, но я согласен, что это плохо   -  person Klaider    schedule 18.11.2016
comment
@FREEZE На самом деле это так. У меня он в отдельном файле, а когда добавляешь 'use strict'; перед if (true), то когда доходит до foo() вылетает ошибка мол "foo is not defined".   -  person krillgar    schedule 18.11.2016
comment
@krillgar Но я проверил это здесь, оно не выдает это исключение, или мой браузер отличается от вашего?   -  person Klaider    schedule 18.11.2016
comment
Связанный документ: ecma-international.org/ecma-262/5.1/ #сек-10.5   -  person Caramiriel    schedule 18.11.2016
comment
@FREEZE У меня Chrome v54. Я попробовал это в Fiddle, и он также выдал ошибку консоли.   -  person krillgar    schedule 18.11.2016
comment
@krillgar Я попробовал сейчас, и это сработало, странно, теперь я получил такое же исключение   -  person Klaider    schedule 18.11.2016
comment
Почему вы пишете такой код?   -  person    schedule 18.11.2016


Ответы (2)


Код, который у вас есть, недействителен в строгом режиме. Функции не поднимаются из блоков (или, по крайней мере, не должны), объявления функций внутри блоков были полностью незаконными до ES6. Вы должны написать

"use strict";
var foo;
if (true) {
  foo = function() {
    alert(1)
  };
} else {
  foo = function() {
    alert(2)
  };
}
foo()

чтобы получить желаемое поведение с воспроизводимыми и ожидаемыми результатами.

Я что-то пропустил или консоль перестала подниматься на fxn!

Похоже, V8 был обновлен, чтобы соответствовать спецификации ES6. Он «поднимает» их в область функций/верхней части, но только тогда, когда объявление действительно встречается (в вашем случае, условно).

person Bergi    schedule 18.11.2016
comment
Итак, теперь — с ES6 — это недействительно? Обратите внимание, что другие клиенты интерпретируют здесь foo как объявление функции, перезаписывая первое foo вторым и в результате получая 2, а не 1 - это было дано в ссылке, на которую ответил @str. - person Vivek Chandra; 18.11.2016
comment
Кроме того, в неаккуратном режиме - до тех пор, пока v8 не получил обновление ES6, объявления fxn внутри блоков были действительными. Из того, что вы говорите, подъем работает, но с этим нужно столкнуться. - person Vivek Chandra; 18.11.2016
comment
@VivekChandra Во-первых, это никогда не было действительным. В строгом режиме ES5 возникала синтаксическая ошибка. Функциональные операторы и подобные вещи были проприетарными расширениями, которые работали только в небрежном режиме, но по-другому. в каждом двигателе. ES6 стандартизировал объявления функций, которые поднимаются до блочной области, а также указал способ веб-совместимости для помещения их в область действия функции, что поддерживает работу обычных устаревших способов использования. - person Bergi; 18.11.2016

Вам следует избегать использования условно созданных функций.

Например, предположим следующий код:

if (false){
 function foo(){
  console.log(1)
 }
}
foo()

Firefox не поднимет функцию, и это приведет к ошибке ReferenceError: foo is not defined. Тем не менее, Chrome поднимает функцию и печатает 1. Итак, очевидно, что вы имеете дело с другим поведением браузера. Поэтому вообще не делайте подобных вещей (или используйте функциональные выражения, если очень хотите).

См. также https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function

Функции могут быть объявлены условно, то есть оператор функции может быть вложен в оператор if. Большинство браузеров, кроме Mozilla, будут рассматривать такие условные объявления как безусловное объявление и создавать функцию независимо от того, истинно условие или нет, см. эту статью для обзора. Поэтому их не следует использовать, для условного создания используйте функциональные выражения.

Особенно посмотрите на связанную статью, которая несколько объясняет проблему, которую вы видите. Так что Chrome, похоже, что-то изменил в этом отношении. Но опять же, не используйте условно созданные функции.

И обратите внимание, что, как прокомментировал FREEZE, вы должны использовать 'use strict';, который не разрешит такой код, а вместо этого выдаст исключение.

person str    schedule 18.11.2016
comment
Вы также можете заметить, что в строгом режиме это также приведет к ошибке ReferenceError. - person Klaider; 18.11.2016
comment
@FREEZE Хороший улов, я добавил комментарий. - person str; 18.11.2016
comment
@str - большое спасибо. Искал эту статью. Chrome, кажется, что-то изменил в этом отношении — я хотел знать, что это за изменение. Я знаю, что мы должны использовать выражения fxn. Как говорит Берги, похоже, природа подъема изменилась. - person Vivek Chandra; 18.11.2016
comment
@VivekChandra Может быть, вы найдете что-то в примечаниях к выпуску или, скорее, в журнале изменений. - person str; 18.11.2016