Появление области блока
Переменные, объявленные через var, имеют продвижение переменной:
if (condition) {
var value = 1;
}
console.log(value);
Новички могут подумать, что значение будет создано только тогда, когда условие истинно. Если условие ложно, результатом должна быть ошибка. Однако из-за продвижения переменных код эквивалентен следующему:
var value;
if (condition) {
value = 1;
}
console.log(value);
Если условие ложно, результат будет неопределенным.
Кроме того, в цикле for:
for (var i = 0; i < 10; i++) {
...
}
console.log(i); // 10
Даже после завершения цикла мы все еще можем получить доступ к значению i.
Чтобы улучшить контроль над временем жизни переменных, в ECMAScript 6 введена область видимости на уровне блоков.
Область действия блока существует в:
- внутри функции
- в блоке (область между символами { и })
пусть и const
Объявления на уровне блока используются для объявления переменных, недоступных за пределами указанного блока.
И let, и const являются типами объявлений блочного уровня.
Давайте рассмотрим характеристики let и const:
1. Не будет продвижения
if (false) {
let value = 1;
}
console.log(value); // Uncaught ReferenceError: value is not defined
2. Повторная ошибка заявления
var value = 1;
let value = 2; // Uncaught SyntaxError: Identifier 'value' has already been declared
3. Не привязывайте глобальную область видимости
При объявлении с var в глобальной области видимости новая глобальная переменная создается как свойство глобального объекта.
var value = 1;
console.log(window.value); // 1
Однако пусть и const не делают:
let value = 1;
console.log(window.value); // undefined
Давайте поговорим о разнице между let и const:
const используется для объявления константы, значение которой нельзя изменить после ее установки, иначе будет сообщено об ошибке.
Стоит отметить: объявления const не позволяют изменять привязки, но позволяют изменять значения. Это означает, что когда объект объявлен с константой:
const data = {
value: 1
}
// 没有问题
data.value = 2;
data.num = 3;
// 报错
data = {}; // Uncaught TypeError: Assignment to constant variable.
Временная мертвая зона
Временная мертвая зона, сокращенно TDZ.
Переменные, объявленные с помощью let и const, не поднимаются в начало области видимости, и доступ к этим переменным до объявления приведет к ошибке:
console.log(typeof value); // Uncaught ReferenceError: value is not defined
let value = 1;
Это связано с тем, что механизм JavaScript при сканировании кода на наличие объявлений переменных либо поднимает их наверх области видимости (где встречаются объявления var), либо помещает объявления в TDZ (где встречаются объявления let и const). Доступ к переменным в TDZ вызывает ошибку времени выполнения. Только после того, как оператор объявления переменной будет выполнен, переменная будет перемещена из TDZ, прежде чем к ней можно будет получить доступ.
Кажется простым для понимания, но не гарантирует, что вы не сделаете ошибок:
var value = "global";
// 例子1
(function() {
console.log(value);
let value = 'local';
}());
// 例子2
{
console.log(value);
const value = 'local';
};
В обоих примерах результат выводит не "глобальный", а ошибкуUncaught ReferenceError: value is not defined
, из-за ТДЗ.
Область блока в циклах
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 3
Обычный вопрос на собеседовании, решение следующее:
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = (function(i){
return function() {
console.log(i);
}
}(i))
}
funcs[0](); // 0
Let ES6 предлагает новое решение этой проблемы:
var funcs = [];
for (let i = 0; i < 3; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 0
Проблема в том, что let не продвигается выше, не может быть объявлен повторно, не может быть привязан к глобальной области видимости и т. д., но почему здесь может быть правильно напечатано значение i?
Если объявление не повторяется, а i объявлено с помощью let во второй раз в цикле, следует сообщить об ошибке.Даже если повторное объявление по какой-то причине не сообщает об ошибке, значение i должно быть 3 в цикле. конец после повторения снова и снова Некоторые люди говорят, что для цикла Часть, которая устанавливает переменную цикла, представляет собой отдельную область, например:
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
Этот пример правильный, что, если мы изменим let на var ?
for (var i = 0; i < 3; i++) {
var i = 'abc';
console.log(i);
}
// abc
Почему результат отличается?Если есть отдельная область, результат должен быть таким же...
Если вы хотите решить эту проблему, вы должны отказаться от этих характеристик, упомянутых ранее! Это связано с тем, что поведение объявлений let внутри циклов специально определено в стандарте и не обязательно связано с неподъемной функцией let.На самом деле, это поведение не было включено в ранние реализации let.
мы смотримРаздел 13.7.4.7 спецификации ECMAScript:
Мы обнаружим, что при использовании let и var в цикле for нижележащий слой будет обрабатываться по-другому.
Итак, что именно делает нижний слой при использовании let?
Проще говоря, этоfor (let i = 0; i < 3; i++)
, который создает скрытую область внутри круглых скобок, что объясняет, почему:
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
потомНовая переменная создается каждый раз при повторении цикла и инициализируется значением одноименной переменной из предыдущей итерации.. Итак, для следующего фрагмента кода
var funcs = [];
for (let i = 0; i < 3; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 0
эквивалентно:
// 伪代码
(let i = 0) {
funcs[0] = function() {
console.log(i)
};
}
(let i = 1) {
funcs[1] = function() {
console.log(i)
};
}
(let i = 2) {
funcs[2] = function() {
console.log(i)
};
};
Когда функция выполняется, правильное значение может быть найдено в соответствии с лексической областью видимости.На самом деле вы также можете понять, что оператор let имитирует метод закрытия, чтобы упростить процесс зацикливания.
let и const в циклах
Но это еще не конец, что, если мы изменим let на const?
var funcs = [];
for (const i = 0; i < 10; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // Uncaught TypeError: Assignment to constant variable.
Результатом будет ошибка, потому что, хотя мы каждый раз создаем новую переменную, мы пытаемся изменить значение const в итерации, поэтому в итоге получим ошибку.
После разговора об обычном цикле for у нас все еще есть цикл for in~
Какой результат ниже?
var funcs = [], object = {a: 1, b: 1, c: 1};
for (var key in object) {
funcs.push(function(){
console.log(key)
});
}
funcs[0]()
Результат «с»;
Что, если вы измените var на let или const?
С let результатом, естественно, будет «a», а как насчет const? Ошибка или «а»?
В результате 'a' печатается правильно, потому что в цикле for in каждая итерация не изменяет существующую привязку, а вместо этого создает новую привязку.
Babel
Как let и const компилируются в Babel? Давайте посмотрим на скомпилированный код:
let value = 1;
компилируется в:
var value = 1;
Мы видим, что Babel компилирует let прямо в var, если это так, давайте напишем пример:
if (false) {
let value = 1;
}
console.log(value); // Uncaught ReferenceError: value is not defined
Если он скомпилирован непосредственно в var, выводимый результат должен быть неопределенным, но Babel очень умен, он компилируется в:
if (false) {
var _value = 1;
}
console.log(value);
Давайте напишем еще один интуитивно понятный пример:
let value = 1;
{
let value = 2;
}
value = 3;
var value = 1;
{
var _value = 2;
}
value = 3;
Суть та же, то есть изменить имя переменной, чтобы имена переменных внутреннего и внешнего слоев были разными.
Как сообщать об ошибках при изменении значений типа const и как сообщать об ошибках при повторении объявлений?
На самом деле, это выдаст вам ошибку непосредственно при компиляции...
Как насчет оператора let в цикле?
var funcs = [];
for (let i = 0; i < 10; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 0
Babel умело компилируется в:
var funcs = [];
var _loop = function _loop(i) {
funcs[i] = function () {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
funcs[0](); // 0
Лучшие практики
Когда мы разрабатывали, мы могли подумать, что должны использовать let вместо var по умолчанию, и в этом случае мы должны использовать const для переменных, которые должны быть защищены от записи. Набирает популярность еще один подход: используйте const по умолчанию и используйте let только тогда, когда вам действительно нужно изменить значение переменной. Это связано с тем, что значение большинства переменных не должно изменяться после инициализации, а неожиданные изменения переменных являются источником многих ошибок.
серия ES6
Адрес каталога серии ES6:GitHub.com/ в настоящее время имеет бриз…
Ожидается, что в серии ES6 будет написано около 20 статей, направленных на углубление понимания некоторых точек знаний ES6, с акцентом на область действия на уровне блоков, шаблоны меток, функции стрелок, реализацию моделирования символов, наборов, карт и обещаний, схему загрузки модулей, асинхронность. обработка и т.п. содержание.
Если есть какие-либо ошибки или неточности, пожалуйста, поправьте меня, большое спасибо. Если вам нравится или у вас есть вдохновение, добро пожаловать в звезду, что также является поощрением для автора.