Какой из двух (или ни одного / обоих) фрагментов кода ниже должен работать в полной реализации ECMAScript 2015:
for (const e of a)
for (const i = 0; i < a.length; i += 1)
Насколько я понимаю, первый пример должен работать, потому что e
он инициализируется для каждой итерации. Разве это не должно происходить и i
во второй версии?
Я смущен, потому что существующие реализации (Babel, IE, Firefox, Chrome, ESLint) не кажутся последовательными и имеют полную реализацию const
с различным поведением двух вариантов цикла; Я также не могу найти конкретный пункт в стандарте, так что я буду очень признателен.
javascript
for-loop
scope
constants
ecmascript-6
Адрианп
источник
источник
prefer-const
опцией), а второй - недействительным. Большинство реализаций браузеров считают оба примера недопустимыми.{const i = 0; while(i < a.length) { /* for body */ i += 1}}
Ответы:
Следующий цикл for-of работает:
for (const e of a)
Спецификация ES6 описывает это как:
http://www.ecma-international.org/ecma-262/6.0/index.html#sec-for-in-and-for-of-statements-static-semantics-boundnames
Императив цикла for работать не будет:
for (const i = 0; i < a.length; i += 1)
Это связано с тем, что объявление оценивается только один раз перед выполнением тела цикла.
http://www.ecma-international.org/ecma-262/6.0/index.html#sec-for-statement-runtime-semantics-labelledevaluation
источник
for
цикла.const ...
это не выражение. Вам нужно посмотреть на правило дляfor ( LexicalDeclaration Expression ; Expression) Statement
.const
s не объявляются повторно для каждой итерации.for (const e of a)
НЕ работает в последней версии Firefox. Я получаюSyntaxError: invalid for/in left-hand side
На этот раз я не буду цитировать спецификацию, потому что думаю, что легче понять, что происходит на примере.
В основном эквивалентен
{ const __it = a[Symbol.iterator](); let __res; while ((__res = __it.next()) && !__res.done) { const e = __res.value; … } }
Для простоты я проигнорировал наличие TDZ с
e
дляa
выражения и различных вызовов__it.return()
/__it.throw(e)
в случае преждевременного выхода из цикла (break
илиthrow
в теле).в основном эквивалентен
{ const i = 0; while (i < a.length) { … i += 1; } }
В отличие от
let
,const
объявление вfor
цикле не объявляется повторно на каждой итерации цикла (и инициализатор в любом случае не выполняется повторно). Если вы неbreak
в первой итерации, вашi +=
будет брошен сюда.источник
const
имеетvar
-подобную область видимости и не передает назначение. Используйте строгий режим.while ( ( __res = __it.next() ) && !__res.done) {
. В противном случае в__res
конечном итоге будетtrue
илиfalse
Ваш второй пример определенно не должен работать, потому что
i
он объявляется один раз, а не на каждой итерации, это просто функция того, как работает эта категория циклов.Вы можете попробовать это в обычном браузере:
for (var i = 0, otherVar = ""; i < [1,2,3,4].length; i += 1){ console.log(otherVar) otherVar = "If otherVar was initialized on each iteration, then you would never read me."; }
Это не тот случай, который
const
полностью запрещен вfor
циклах. Толькоfor
это изменит const.Они действительны:
for(const i = 0;;){ break } for(const i = 0; i < 10;){ break; }
Они недействительны:
for(const i = 0;;){ ++i; break; } for(const i = 0;;++i){ if(i > 0) break; }
Я не уверен, почему Firefox выдает SyntaxError после прочтения спецификации ES2015 (хотя я уверен, что умники из Mozilla правы), похоже, что он должен вызвать исключение:
источник
const
а не дляlet
?const
не позволяет переназначить себя (это не оспаривается), и, как мой пример, ясно демонстрирует, какfor
работает для части определения переменной вопреки его подразумеваемым ожиданиям. Значениеlet
можно изменить, оно функционально эквивалентно приведенномуvar
в примере, ноlet
не является частью вопроса.const i
это объявляется только один раз, ноlet i
нет? Ваш пример только демонстрирует, какvar i
работает, а неconst i
. Поскольку существует четкая разница междуvar
,const
иlet
, я думаю, что ссылка на его спецификацию в отношении них былаconst
бы очень ценной.const
значение может быть присвоено только один раз, любая попытка повторного объявленияconst
не будет работать. Мой пример - продемонстрировать тот факт, что объявление происходит только один раз, и человек, задающий вопросы, понимает семантикуconst
.let
не проблема, и нет, я явно не имел в виду то, что вы предлагаете, вы неправильно прочитали.let
, то на каждой итерации будет свой экземплярi
.for(let foo = 0; i < 10; ++i){}
эквивалентно(funtion() { for(var i = 0; i < 10; ++i){ (function(i) { }(i)) } }());
This is where I am from:let
иconst
оба имеют блочную область видимости.for/in
иfor/of
выставляем такое же поведение дляconst
иlet
, но в обычномfor
цикле этого не происходит. Он явно по-const
разному относится (возможно, понятно). Вы просто говорите, что он «объявляется один раз», но это слишком упрощает ИМО.