Переменные, объявленные с 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
в этом вопросе?
Ответы
Ответ 1
@thethethethe верно, говоря, что эти переменные не могут быть доступны, прежде чем они будут объявлены. Однако это немного сложнее, чем это.
Не объявлены ли переменные, объявленные с помощью 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
declara & shy;, это инициализация .
Первые инициализируются с помощью функции 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;
.
Временная мертвая зона не является синтаксическим расположением, а скорее временем между созданием переменной (области) и инициализацией. Это не ошибка ссылки на переменную в коде выше объявления, если этот код не выполняется (например, тело функции или просто мертвый код), и он будет генерировать исключение, если вы получите доступ к переменной до инициализации, даже если доступ код ниже декларации (например, в объявлении с функцией hoisted, которое называется слишком ранним).
Есть ли разница между let
и const
в этом вопросе?
Нет, они работают так же, как и подъем. Единственная разница между ними заключается в том, что const
ant должен быть назначен и может быть назначен только в части инициализации объявления (const one = 1;
, как const one;
, так и более поздние переопределения, такие как one = 2
).
1: var
объявления все еще работают только на уровне функции, конечно
Ответ 2
Цитирование спецификации ECMAScript 6 (ECMAScript 2015) спецификации, let
и const
,
Переменные создаются, когда создается экземпляр их содержащей Lexical Environment, но к ним нельзя обращаться каким-либо образом, пока не будет оценена переменная LexicalBinding.
Итак, чтобы ответить на ваш вопрос, да, let
и const
hoist, но вы не можете получить к ним доступ, пока фактическое объявление не будет оценено во время выполнения.
Ответ 3
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([])
Ответ 4
Из веб-документов MDN:
В ECMAScript 2015 let
и const
поднимаются, но не инициализируются. Ссылка на переменную в блоке до ее объявления приводит к возникновению ReferenceError
поскольку переменная находится в "временной мертвой зоне" с начала блока до обработки объявления.
console.log(x); // ReferenceError
let x = 3;
Ответ 5
- В случае var, после создания определений переменных, перед выполнением построчно каждая из переменных инициализируется с неопределенным значением.
- В случае let/const, инициализация в undefined не происходит до тех пор, пока не произойдет строка, на которой фактически происходит объявление.
Доступ к переменной до инициализации приводит к ReferenceError. Переменная находится во "временной мертвой зоне" от начала блока до обработки инициализации.
console.log(typeof name); // No intialization till now => referenceError
let name = "John";