Серия ES6 let и const

внешний интерфейс GitHub Babel ECMAScript 6
Серия ES6 let и const

Появление области блока

Переменные, объявленные через 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 规范

Мы обнаружим, что при использовании 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, с акцентом на область действия на уровне блоков, шаблоны меток, функции стрелок, реализацию моделирования символов, наборов, карт и обещаний, схему загрузки модулей, асинхронность. обработка и т.п. содержание.

Если есть какие-либо ошибки или неточности, пожалуйста, поправьте меня, большое спасибо. Если вам нравится или у вас есть вдохновение, добро пожаловать в звезду, что также является поощрением для автора.

Категории