Что вызывает различное поведение между var и let при назначении им возвращаемого значения функции, которая выдает ошибку

Пожалуйста, найдите код на изображении ниже. 1. Присвойте возвращаемое значение функции, которая на самом деле выдает ошибку, переменной withLet, объявленной с помощью ключевого слова let. 2. вызов 'withLet', произошла ошибка: 'withLet не определен'. 3. попробуйте утвердить 'withLet' с помощью 'let', ошибка показывает, что 'withLet' уже объявлен.

Но парадокс не существует для «var» (пожалуйста, найдите на следующем изображении).

Мне любопытно, что вызвало различное поведение между этими двумя ситуациями. Довольно запутанно, что «не определено» и «уже объявлено» описывают одну и ту же переменную.

let withLet = (function() {throw 'error!'})()
var withVar = (function() {throw 'error!'})()
//VM2470:1 Uncaught error!
//(anonymous) @ VM2470:1
//(anonymous) @ VM2470:1
withLet
//VM2484:1 Uncaught ReferenceError: withLet is not defined at 
//<anonymous>:1:1
//(anonymous) @ VM2484:1
withVar
//undefined
let withLet = 'sth'
//VM2520:1 Uncaught SyntaxError: Identifier 'withLet' has already been 
//declared
//at <anonymous>:1:1
//(anonymous) @ VM2520:1
withVar = 'sth'
//"sth"

Скриншот:


person Heyi    schedule 17.01.2019    source источник
comment
Firefox просто печатает undefined.   -  person Chris G    schedule 17.01.2019
comment
Chrome выдает errors! для каждого вызова функции   -  person Cid    schedule 17.01.2019
comment
я думаю это глюк движка. withLet должен быть инициализирован, а undefined, но из-за характера области видимости переменной он, вероятно, обрабатывает его по-разному.   -  person venimus    schedule 17.01.2019
comment
здесь важное уточнение - это происходит в Chrome/V8, но не в Firefox. Итак, это поведение, специфичное для реализации.   -  person VLAZ    schedule 17.01.2019


Ответы (1)


Объявления var переменных поднимаются — инициализация имени переменной поднимается в начало содержащей ее функции (или, если функции нет, в начало внешнего блока). Так

var withVar = (function() {throw 'error!'})()

анализируется интерпретатором как

var withVar;
withVar = (function() {throw 'error!'})()

То же самое не верно для let - переменные let инициализируются после запуска строки let __. Когда есть присваивание, сначала анализируется правая часть; если правая часть выдает ошибку, она никогда не попадает в левую часть, а переменная, объявленная с помощью let, никогда не инициализируется должным образом; он навсегда останется в демилитаризованной/временной мертвой зоне, поэтому попытка переназначить его выдает ошибку.

Это немного странно, потому что код запускается в консоли — обычно JS запускается внутри тега <script>, и если возникает такая ошибка, обычно код больше не запускается , а тот факт, что переменная, объявленная с помощью let, больше не может быть переназначена, вас меньше всего беспокоит.


Вышеупомянутая проблема была в более ранних версиях Chrome. Но в Chrome 80+ повторное объявление let теперь разрешено. , поэтому ошибка

Uncaught SyntaxError: идентификатор withLet уже объявлен

больше не должно происходить, независимо от того, была ли предыдущая инициализация переменной успешной или нет:

введите здесь описание изображения

person CertainPerformance    schedule 17.01.2019
comment
Просто немного расширимся: переменная проходит три этапа, прежде чем стать реальной. Декларация (идентификатор существует), инициализация (идентификатор активен и может быть использован), присвоение (значение, присвоенное этому идентификатору). Для var поднята декларация + инициализация. Для let/const поднимается только декларация, инициализация происходит позже - как указано, при достижении строки let myVar. - person VLAZ; 17.01.2019