Переменные, объявленные с помощью let или const, не отображаются в ES6?
Я некоторое время играл с ES6 и заметил, что переменные объявлены с var
подняты как положено...
console.log(typeof name); // undefined
var name = "John";
... переменные объявлены с let
или же const
похоже, есть некоторые проблемы с подъемом:
console.log(typeof name); // ReferenceError
let name = "John";
а также
console.log(typeof name); // ReferenceError
const name = "John";
Означает ли это, что переменные объявлены с let
или же const
не подняты? Что на самом деле здесь происходит? Есть ли разница между let
а также const
в этом вопросе?
9 ответов
@thefourtheye правильно говорит, что эти переменные не могут быть доступны до их объявления. Тем не менее, это немного сложнее, чем это.
Переменные объявлены с
let
или жеconst
не лапы? Что на самом деле здесь происходит?
Все объявления (var
, let
, const
, function
, function*
, class
) "подняты" в JavaScript. Это означает, что если имя объявляется в области, в этой области идентификатор всегда будет ссылаться на эту конкретную переменную:
x = "global";
// function scope:
(function() {
x; // not "global"
var/let/… x;
}());
// block scope (not for `var`s):
{
x; // not "global"
let/const/… x;
}
Это верно как для функциональных, так и для блочных областей 1.
Разница между var
/ function
/ function*
декларации и let
/ const
/ class
объявления это инициализация.
Первые инициализируются с undefined
или (генератор) функция прямо, когда привязка создается в верхней части области. Однако лексически объявленные переменные остаются неинициализированными. Это означает, что ReferenceError
исключение выдается при попытке доступа к нему. Инициализируется только тогда, когда let
/ const
/ class
Оператор оценивается, все до (выше), что называется временной мертвой зоной.
x = y = "global";
(function() {
x; // undefined
y; // Reference error: y is not defined
var x = "local";
let y = "local";
}());
Обратите внимание, что let y;
оператор инициализирует переменную с undefined
лайк let y = undefined;
будет иметь.
Временная мертвая зона - это не синтаксическое местоположение, а время между созданием переменной (области действия) и инициализацией. Ссылка на переменную в коде над объявлением не является ошибкой, если этот код не выполняется (например, тело функции или просто мертвый код), и будет выдано исключение, если вы получите доступ к переменной до инициализации, даже если доступ код находится ниже объявления (например, в объявлении поднятой функции, которое вызывается слишком рано).
Есть ли разница между
let
а такжеconst
в этом вопросе?
Нет, они работают так же, как считается подъем. Единственная разница между ними заключается в том, что const
Муравей должен быть и может быть назначен только в инициализирующей части объявления (const one = 1;
, и то и другое const one;
а потом переназначения вроде one = 2
недействительны).
1: var
декларации все еще работают только на уровне функций, конечно
Цитирование спецификаций ECMAScript 6 (ECMAScript 2015), let
а также const
раздел объявлений,
Переменные создаются, когда создается экземпляр их содержащей Lexical Environment, но к ним нельзя получить доступ, пока не будет оценена переменная LexicalBinding.
Итак, чтобы ответить на ваш вопрос, да, let
а также const
Поднимите, но вы не можете получить к ним доступ до того, как фактическое объявление будет оценено во время выполнения.
ES6
вводит Let
переменные, которые приходят с block level scoping
, До тех пор ES5
у нас нет block level scoping
поэтому переменные, объявленные внутри блока, всегда hoisted
для определения уровня работы.
В принципе Scope
указывает, где в вашей программе видны ваши переменные, что определяет, где вам разрешено использовать объявленные вами переменные. В ES5
у нас есть global scope,function scope and try/catch scope
, с ES6
мы также получаем определение уровня блока, используя Let.
- Когда вы определяете переменную с
var
Ключевое слово, известно всю функцию с момента ее определения. Когда вы определяете переменную с
let
Заявление это известно только в блоке, он определен.function doSomething(arr){ //i is known here but undefined //j is not known here console.log(i); console.log(j); for(var i=0; i<arr.length; i++){ //i is known here } //i is known here //j is not known here console.log(i); console.log(j); for(let j=0; j<arr.length; j++){ //j is known here } //i is known here //j is not known here console.log(i); console.log(j); } doSomething(["Thalaivar", "Vinoth", "Kabali", "Dinesh"]);
Если вы запустите код, вы можете увидеть переменную j
известен только в loop
а не до и после. Тем не менее, наша переменная i
известен в entire function
с момента, когда это определено.
Есть еще одно большое преимущество использования let, поскольку оно создает новую лексическую среду, а также связывает новую ценность, а не сохраняет старую ссылку.
for(var i=1; i<6; i++){
setTimeout(function(){
console.log(i);
},1000)
}
for(let i=1; i<6; i++){
setTimeout(function(){
console.log(i);
},1000)
}
Первый for
цикл всегда печатает последнее значение, с let
это создает новую область и связывает новые ценности, печатая нас 1, 2, 3, 4, 5
,
Подходит к constants
работает в принципе как let
Разница лишь в том, что их значение не может быть изменено. В константах мутация разрешена, но переназначение не допускается.
const foo = {};
foo.bar = 42;
console.log(foo.bar); //works
const name = []
name.push("Vinoth");
console.log(name); //works
const age = 100;
age = 20; //Throws Uncaught TypeError: Assignment to constant variable.
console.log(age);
Если константа относится к object
, это всегда будет относиться к object
но object
сам может быть изменен (если он изменчив). Если вам нравится иметь неизменный object
Вы могли бы использовать Object.freeze([])
Согласно ECMAScript® 2021
Объявления Let и Const
- Объявления let и const определяют переменные, которые ограничены LexicalEnvironment текущего контекста выполнения.
- Переменные создаются при создании экземпляра содержащейся в них записи среды, но к ним нельзя получить доступ каким-либо образом до тех пор, пока не будет вычислена LexicalBinding переменной.
- Переменной, определенной LexicalBinding с инициализатором, присваивается значение AssignmentExpression ее инициализатора при оценке LexicalBinding, а не при создании переменной.
- Если LexicalBinding в объявлении let не имеет инициализатора, переменной присваивается значение undefined при оценке LexicalBinding.
Блокировать создание объявления
- Когда блок или CaseBlock оценивается, создается новая декларативная запись среды, и привязки для каждой переменной, константы, функции или класса, объявленные в блоке, создаются в записи среды.
- Независимо от того, как контроль покидает блок, LexicalEnvironment всегда возвращается в свое прежнее состояние.
Лексически объявленные имена верхнего уровня
На верхнем уровне функции или скрипта объявления функций обрабатываются как объявления var, а не как лексические объявления.
Вывод
- let и const поднимаются, но не инициализируются.
Ссылка на переменную в блоке перед объявлением переменной приводит к ошибке ReferenceError, потому что переменная находится во "временной мертвой зоне" от начала блока до обработки объявления.
Примеры ниже проясняют, как переменные "let" ведут себя в лексической / вложенной лексической области видимости.
Пример 1
var a;
console.log(a); //undefined
console.log(b); //undefined
var b;
let x;
console.log(x); //undefined
console.log(y); // Uncaught ReferenceError: y is not defined
let y;
Переменная 'y' выдает ошибку referenceError, что не означает, что она не поднята. Переменная создается при создании экземпляра окружающей среды. Но к нему нельзя получить доступ, потому что он находится в недоступной "временной мертвой зоне".
Пример 2
let mylet = 'my value';
(function() {
//let mylet;
console.log(mylet); // "my value"
mylet = 'local value';
})();
Пример 3
let mylet = 'my value';
(function() {
let mylet;
console.log(mylet); // undefined
mylet = 'local value';
})();
В примере 3 недавно объявленная переменная mylet внутри функции не имеет инициализатора перед оператором журнала, следовательно, значение undefined.
Источник
В ECMAScript 2015, let
а также const
подняты, но не инициализированы. Ссылка на переменную в блоке перед объявлением переменной приводит кReferenceError
потому что переменная находится во "временной мертвой зоне" от начала блока до обработки объявления.
console.log(x); // ReferenceError
let x = 3;
В es6, когда мы используем let или const, мы должны объявить переменную перед их использованием. например. 1 -
// this will work
u = 10;
var u;
// this will give an error
k = 10;
let k; // ReferenceError: Cannot access 'k' before initialization.
например. 2-
// this code works as variable j is declared before it is used.
function doSmth() {
j = 9;
}
let j;
doSmth();
console.log(j); // 9
Я думаю, это может ответить на этот вопрос
В JavaScript переменные, объявленные с помощью и, поднимаются, но их поведение отличает их от переменных, объявленных с помощью .
Подъем означает, что объявления переменных перемещаются в начало содержащей их функции или области действия блока на этапе компиляции. Однако есть ключевое различие между , и с точки зрения подъема:
- переменные поднимаются и инициализируются значением . Это означает, что вы можете ссылаться на
var
переменная до ее объявления, и она будет иметь значениеundefined
в таком случае.
console.log(x); // undefined
var x = 10;
- и переменные также поднимаются, но не инициализируются. Если вы попытаетесь получить к ним доступ до их объявления, вы получите «ReferenceError».
console.log(x); // ReferenceError: x is not defined
let x = 10;
Таким образом, хотя оба и подняты в начало области их блока или функции, вы не можете получить к ним доступ до их объявления из-за поведения временной мертвой зоны (TDZ). Такое поведение было введено для выявления потенциальных ошибок и повышения предсказуемости кода.
Временная мертвая зона (ВМЗ)
Временная мертвая зона (TDZ) — это концепция в JavaScript, связанная с объявлениями переменных с использованием ключевых слов и. Это этап в контексте выполнения JavaScript, который происходит во время инициализации переменной, прежде чем переменной будет присвоено значение. Понимание TDZ имеет решающее значение для предотвращения непредвиденного поведения вашего кода.
Вот как работает временная мертвая зона:
Объявление переменной. Когда вы объявляете переменную с помощью или , механизм JavaScript устанавливает привязку для этой переменной в текущей области. Это означает, что переменная известна движку, но еще не инициализирована.
Инициализация: переменные, объявленные с помощью TDZ, остаются неинициализированными до тех пор, пока им не будет присвоено значение с помощью
=
оператор.Доступ до инициализации. Попытка получить доступ к переменной, объявленной до того, как ей было присвоено значение, или сослаться на нее, приведет к
ReferenceError
. Это связано с тем, что переменная существует в TDZ, и доступ к ней в этом состоянии запрещен.
Вот пример, иллюстрирующий временную мертвую зону:
console.log(x); // Throws a ReferenceError
let x = 10;
В этом примере мы пытаемся зарегистрировать значение до его объявления и инициализации. Это приводит к ошибке ReferenceError, поскольку находится во временной мертвой зоне в точкеconsole.log()
заявление.
Чтобы избежать временной мертвой зоны, рекомендуется всегда объявлять переменные в верхней части текущей области перед их использованием. Например:
let x; // Declare x at the top of the scope
console.log(x); // undefined (no error)
x = 10; // Initialize x
В этом модифицированном кодеx
объявлен в верхней части области видимости, что означает, что он все еще находится в TDZ, когда мы его регистрируем, но он не выдает ошибку, поскольку мы не пытаемся получить доступ к его значению перед объявлением.
Итак, временная мертвая зона — это механизм в JavaScript, который предотвращает доступ к переменным, объявленным с помощьюlet
илиconst
прежде чем они будут инициализированы. Это помогает выявить потенциальные ошибки, связанные с использованием переменных, и поощряет более эффективные методы кодирования, продвигая объявления переменных в начале их соответствующих областей.
let и const также поднимаются. Но будет выдано исключение, если переменная, объявленная с помощью let или const, будет прочитана до ее инициализации по причинам, указанным ниже.
- В отличие от var, они не инициализируются значением по умолчанию при подъеме.
- Они не могут быть прочитаны/записаны, пока они не будут полностью инициализированы.
- В случае var, после создания определений переменных, перед выполнением построчно каждая из переменных инициализируется с неопределенным значением.
- В случае let/const, инициализация в undefined не происходит до тех пор, пока не произойдет строка, на которой фактически происходит объявление.
Доступ к переменной до инициализации приводит к ReferenceError. Переменная находится во "временной мертвой зоне" от начала блока до обработки инициализации.
console.log(typeof name); // No intialization till now => referenceError
let name = "John";