2016-11-30 10 views
5

Это было представлено вчера в TC39. Вы можете найти суть here:Нечеткие и закрытые странности в javascript

var p =() => console.log(f); 
{ 
    p(); // undefined 
    console.log(f); // function f(){} 

    f = 1; 

    p(); // undefined 
    console.log(f); // 1 

    function f(){} 

    p(); // 1 
    console.log(f); // 1 

    f = 2; 

    p(); // 1 
    console.log(f); // 2 
} 

Может кто-то пожалуйста, объясните мне, как эта штука работает? Для записи это работает только в нестандартном режиме.

спасибо.

+1

В частности, относительно хостинга? Этот ответ объясняет это очень хорошо: http://stackoverflow.com/questions/25111087/why-is-a-function-declaration-within-a-condition-block-hoisted-to-function-scope – CodingIntrigue

+1

@CodingIntrigue: Нет, который не охватывает то, что происходит выше, что является артефактом Приложения B ES2015 и TC39, которые изо всех сил пытаются справиться с серьезными коварными водами существующего кода и исторически несогласованными реализациями. :-) –

+0

@ T.J.Crowder Уход, чтобы объяснить более подробно? 'function f() {}' обычно будет подниматься внутри нормального функционального блока, а первый 'undefined' должен был напечатать декларацию функции f, но как теперь это определено внутри блока? – kstratis

ответ

2

Я не буду требовать понимания всех тонкостей, но главное в этом почти странные искажения в Приложении B §B.3.3.1.

Этот код эффективно это, где f1 является второй копией f специфичны для лексического окружения блока (отсюда let ниже):

var p =() => console.log(f); 
{ 
    let f1 = function f(){};;   // Note hoisting 
    p(); // undefined 
    console.log(f1); // function f(){} 

    f1 = 1; 

    p(); // undefined 
    console.log(f1); // 1 

    var f = f1;       // !!! 

    p(); // 1 
    console.log(f1); // 1 

    f1 = 2; 

    p(); // 1 
    console.log(f1); // 2 
} 

И, конечно, благодаря var грузоподъемных, как p и f эффективно объявлены в верхней части фрагмента кода с начальным значением undefined:

var f = undefined; 
var p = undefined; 
p =() => console.log(f); 
{ 
    let f1 = function f(){};;   // Note hoisting 
    p(); // undefined 
    console.log(f1); // function f(){} 

    f1 = 1; 

    p(); // undefined 
    console.log(f1); // 1 

    f = f1;        // !!! 

    p(); // 1 
    console.log(f1); // 1 

    f1 = 2; 

    p(); // 1 
    console.log(f1); // 2 
} 

ключ от битового В.3.3.1 заключается в том, что он переносит значение внутреннего f (которое я назвал f1 выше) на внешний (ниже, F - строка "f", название объявляемой функции):

3. Когда FunctionDeclaration е вычисляется, выполнить следующие шаги вместо алгоритма FunctionDeclaration оценки, представленной в 14.1.21:

с. Пусть fenv - переменная среды выполнения контекста выполнения.

b. Пусть fenvRec be fenv's EnvironmentRecord.

c. Пусть benv - это лексическое окружение контекста выполнения выполнения.

d. Пусть benvRec beben's EnvironmentRecord.

e. Let fobj be! benvRec.GetBindingValue (F, false).

f. Выполните! fenvRec.SetMutableBinding (F, fobj, false).

g. Возврат NormalCompletion (пустой).

Напомним, что окружающая среда переменная является функцией шириной, но среда лексической более ограничена (в блоке).

Когда дело доходит до попытки нормализовать объявления функций в местах, где они были {недействительными | unspecified} (выберите ваш термин), TC39 имеют очень предательский путь для навигации, стараясь стандартизировать поведение, не нарушая существующий код, который, возможно, полагался на поведение, специфичное для исполнения, из прошлого (которые были взаимоисключающими, но TC39 пытается добиться баланса).

+0

Не могли бы вы немного подробнее рассказать о первых двух 'p()'? Почему они выходят как «неопределенные»? Этот бит беспокоит меня больше всего; У нас уже есть подъем, и, таким образом, 'f' должен быть уже определен в этой точке ... – kstratis

+1

@kstratis помнит, что подъем не _set_ переменная. Все, что он делает, это изменение объявления, поэтому, если у вас есть, скажите «var x = 5» в строке 10, _in effect_, код «var x;» находится в верхней части файла, а затем 'x = 5' на линии 10. Линии 1-9 по-прежнему будут иметь 'x' равно' undefined', так как значение еще не будет установлено. Таким образом, 'console.log (x)' в строке 4 создаст 'undefined'. Однако, если вы вообще не указали 'var x', это приведет к созданию ReferenceError – vlaz

+1

@kstratis: см. Комментарий vlaz выше. Я также добавил второй фрагмент кода, чтобы сделать это явным. –

 Смежные вопросы

  • Нет связанных вопросов^_^