Объяснение переменных var, let и const в JavaScript

obyasnenie peremennyh var let i const v javascript?v=1656585753

Прортана С. Санномани

dqtsGiSRlWg950TkvenjDVMhKMWgjl3OWxKF
«Коллекция разнообразных деревянных коробок с разнообразными цветочными орнаментами на поверхности красной ткани в Кембридже» Клем Оноджегуо на Unsplash

В этой статье мы рассмотрим историю var JavaScript, потребность в let и constи отличия между ними.

Эта публикация состоит из двух разделов: вымышленного произведения и технического объяснения.

Вымышленное произведение призвано облегчить начинающим представление о понятии, но некоторые части упрощены и не всегда представляют точную аналогию 1:1.

Давайте начнем!

Сказка о трех переменных

Город JavaScript был шумным городом у моря с коммерческим районом, наполненным многоэтажными домами.

С незапамятных времен жители города JavaScript использовали Vary ящики для хранения ценностей, особенно ценных золотых мраморов. Для этого у жителей было два варианта:

  1. Они могут поместить золотые шарики прямо в коробку (передать по значению).
  2. Если у них было большое количество золотых шаров, чтобы они не помещались в коробку, они могли поместить в коробку специальную бумажку, на которой указывалось, где они их хранили. Например, на листе бумаги может быть написан «второй ящик в шкафу для хранения» (передать по ссылке)

Поскольку город гордится правопорядком, они установили несколько правил и процедур.

Правила для магазинов

  1. Чтобы поддерживать спокойствие города, магазины можно было строить только на холмах (функции создают свой локальный масштаб)
  2. Единственным исключением из Правила 1 являлся специальный магазин на уровне моря (глобальный масштаб).
  3. Магазин может иметь внутренние магазины для покрытия арендной платы (вложенные функции). Однако каждый внутренний магазин должен был быть на более высоком холме, чем холм магазина помещика (объем местной функции).
  4. В магазине могут быть прилавки со «специальными предложениями», например «If вам больше 20 лет, купите здесь специальную коробку». И «For (каждый) ребенок of ваша семья, купите здесь детскую коробку” (другие блоки, например if и петли).
  5. Каждый цех должен был иметь прилавок «декларации-инициализации» с охранником на входе, ведущим журнал регистрации (подъем в верхней части соответствующего объема).
  6. Каждый магазин мог иметь неограниченное количество прилавков «назначения» с продавцом, который клал золотые шарики жителя в коробку.

Правила регулирования рынка ящиков

  1. Ящики можно было приобрести только в специальном магазине на уровне моря или магазине на холмах (переменная может иметь глобальный или локальный масштаб).
  2. На уровне моря или на любом холме жители могли обладать ТОЛЬКО одним цветом Vary поле (дублированные идентификаторы не допускаются).
  3. The Vary ящик никогда не может быть пустым с момента его создания. Он должен содержать хлопок (undefined) или золотые мраморы всегда (эффект подъема).
  4. После того, как жилец вышел из магазина (и следовательно спустился с холма), все коробки, которые они приобрели в нем, исчезли (конец области действия переменной).

Порядок покупки жителями ящиков `Vary`

В этой статье мы рассмотрим путешествие жителя Джона.

  1. Джон входит в магазин и заявляет, какого цвета Vary коробку, которую он хочет купить на прилавке «декларирование-инициализация». Об этом охранник отмечает в своей регистрационной книге.
  2. Охранник заклинает цветных Vary коробку, наполняет ее хлопком и передает Джону.
  3. Джон получает билет в свою очередь, и когда он приходит, он направляется к стойке «назначения». К тому времени он может держать свой ящик, но не может поместить в него свои золотые шарики.
  4. У прилавка Джон передает свою коробку и золотые шарики продавцу, который снимает хлопок, кладет золотые шарики внутрь и возвращает ему.

Естественно эти правила принесли с собой особые проблемы.

  1. Долгое время ожидания счетчика назначения Джон забыл бы, что он еще не положил свои золотые шарики в свою коробку. Он открывал его, чтобы похвастаться перед друзьями и находить только хлопок. Облом!
  2. Часто Джон забывал, что уже купил определенную цветную коробку в магазине, и снова регистрировался на коробку того же цвета. Это мгновенно приведет к исчезновению его существующей коробки (и золотых мраморов!!), а затем охранник создаст новую коробку, наполненную хлопком. Без предупреждения! Особенно это было распространено на прилавках со «специальными предложениями».

Вы можете представить, насколько неприятна была эта ситуация. Поскольку жители города JavaScript потеряли свой мрамор, городской совет решил принять меры.

На грандиозной городской встрече 2015 года они с гордостью представили две новые коробки: Lety и Consty.

Они также внесли еще одно важное изменение: изъяли счетчики со специальными предложениями Lety и Consty магазины. Эти прилавки были модернизированы во внутренние магазины, которые были построены на холме внутри магазина.

Правила приобретения коробок `Lety` и `Consty`

  1. Джон заходит в магазин и заявляет, какой тип и цвет коробки хочет купить на прилавке «декларации». Об этом охранник отмечает в своей регистрационной книге. Эта информация туманно появляется на огромных настенных часах, которые можно увидеть, но не использовать, и называется «временной мертвой зоной».
  2. Джон получает билет в свою очередь. Поскольку коробка не создается при декларировании, она недоступна для использования.

Вот где Lety и Consty правила покупки расходятся.

Правила `Lety`:

  1. Как только наступает черед Джона, он направляется к счетчику «инициализации».
  2. У прилавка у Джона есть выбор купить пустой Lety коробку, или купите а Lety ящик и немедленно помести его золотые шарики в него.
  3. В зависимости от выбора продавец заклинает Lety коробку, и наполняет ее хлопком или передает на прилавок «задачу», где внутрь кладут золотые шарики Джона.

Правила `Consty`

Consty коробки есть чрезвычайно особенный. Обложенные изнутри слоем золота и запечатанные замком, эти коробки настолько дороги продавцам, что они отказываются продавать их, не зная, что именно в них поместит.

  1. Как только наступает черед Джона, он направляется к счетчику «инициализация-назначение».
  2. Джон есть требуется передать свои золотые шарики продавцу, заклинающему цветных Consty ящик, помещающий внутрь золотые шарики, и запирает коробку навсегда.

Если вы помните, Джон мог напрямую положить свои золотые шарики в коробку или поместить специальный кусок бумаги, на котором было указано расположение его золотых шаров.

  1. Если он поместит свои золотые шарики внутрь Consty box, он больше не может добавить или удалить их. Они заперты навсегда.
  2. Однако если он помещает специальную бумажку, это несколько иначе. Пока он не может заменить бумаги, он может добавить или удалить свои золотые шарики в месте, которое он указал на бумаге.

Вернемся к своеобразным проблемам, побудившим к изобретению Lety и Consty коробки и решить, решены ли они.

Долгое время ожидания счетчика назначения Джон забыл бы, что он еще не положил свои золотые шарики в свою коробку. Он открывал его, чтобы похвастаться перед друзьями и находить только хлопок. Облом!

Так как Lety и Consty ящики не создаются, пока Джон не перейдет к счетчику «инициализация» или «инициализация-назначение», соответственно, он знает, что у него нет ящика, и, таким образом, не пытается им воспользоваться. Даже если он сделает это, громкие сигнализации, установленные в магазинах, начинают звонить, чтобы предупредить его об этом.

Часто Джон забывал, что уже купил определенную цветную коробку в магазине и снова регистрировался на коробку такого же цвета. Это мгновенно приведет к исчезновению его существующей коробки (и золотых мраморов!!), а затем охранник создаст новую коробку, наполненную хлопком. Без предупреждения! Особенно это было распространено на прилавках со «специальными предложениями».

Это решается путем удаления счетчиков «специальных предложений» и ввода следующего правила:

После того, как житель регистрируется на определенную цветную коробку на стойке «декларации» в Lety или Consty магазинах, он больше не может повторно зарегистрироваться на коробку того же цвета в этом магазине! Если он это сделает, начнут раздаваться громкие будильники.

Эти великолепные новые коробки и правила снова купили мир и покой в ​​JavaScript Town, и все жили долго и счастливо.

Погружение в технические детали

Давайте рассмотрим технические аспекты var, let и const чтобы понять историю.

Если вы не знакомы с подъемом и областью применения (на уровне функции и на уровне блоков), я рекомендую вам прочитать мою предыдущую статью здесь.

Вот выдержка, чтобы понять аналогию с холмами, которую я использовал выше:

Чтобы расширить наше понимание уровня блоков и уровня функции, рассмотрим аналогию холмов. Предположим, что глобальный масштаб – это суша на уровне моря, а локальные – это холмы. Если вы стоите на вершине холма, вы можете видеть (доступать) переменные ниже своей высоты. Однако, если вы находитесь на уровне моря, вы не можете увидеть (получить доступ) переменные на большей высоте.

В C++ каждый блок {} приводит к образованию нового холма (локального масштаба) на высоте на один уровень выше, чем тот, на котором он заключен. Уложенные блоки приводят к многоуровневым холмам.

В JavaScript только функция приводит к формированию нового холма (локальная область видимости). Другие блоки, такие как if блоки находятся на одной высоте.

Следовательно, если переменная объявлена ​​на определенном холме (блоке), доступ к ней можно получить с этого холма (блока) и всех холмов (блоков) над ним.

Жизненный цикл переменной

Этап декларирования: Регистрация переменной в ее области, которая может быть глобальной/функциональной/блочной. На этом шаге память еще не выделена.

Фаза инициализации: выделение памяти для переменной, где создается привязка, а переменная инициализируется undefined.

Фаза назначения: Назначение переменной.

Важно отметить, что объявление переменной и фаза объявления не является одним и тем же!

Объявление переменной – это такой оператор, как var a.

Фаза объявления – это шаг, который выполняет компилятор JavaScript. На этом шаге, когда компилятор встречает переменную, он объявляет/регистрирует ее в соответствующей области (если объявление еще не существует). Позже код, сгенерированный компилятором, выполняется движком JavaScript.

вар

  1. глобальная область или область функции
  2. значение можно обновить
  3. можно повторно объявить
  4. поднято: зарегистрировано в области действия и инициализировано с помощью undefined

Ниже представлен простой пример, где мы инициализируем переменную, обновляем ее значение и повторно объявляем.

// Hoistedconsole.log(a); // undefined
var a = 10;console.log(a); // 10
a = 20; // value updated: OKconsole.log(a); // 20
var a = 30; // re-declared: OKconsole.log(a); // 30

В верхней части области действия все переменные объявляются в соответствующей области и инициализируются значением undefined. Регистрация и инициализация совмещены. Таким образом, переменная a доступный для использования из верхней части диапазона. Итак, когда мы пытаемся получить доступ к значению a до того, как он будет объявлен, он не выдает ошибки. скорее, undefined печатается. Это известно как переменный подъем.

Ниже приведен пример, показывающий область действия функции var.

function outerFunc() {  var a = 10;  if (a > 5) {    var a = 20;    console.log(a); // 20  }  console.log(a); // 20}

Переменная a сначала объявляется в области применения outerFunc. Поскольку if блок не создает новую область, когда мы повторно объявляем переменную aпредыдущая переменная a удаляется и создается новая переменная a создается со значением 20.

Случайное повторное декларирование var переменные являются распространенной ошибкой разработчиков из-за молчаливого повторного объявления и путаницы в понимании области действия функции.

разрешает

  1. область действия блока
  2. значение можно обновить
  3. не могут быть повторно объявлены
  4. поднято, но не инициализировано

Ниже приведен простой пример, где мы инициализируем переменную, обновляем ее значение и стараемся повторно объявить ее.

console.log(a); //   ReferenceError: a is not defined
let a = 10;console.log(a); // 10
a = 20;console.log(a); // 20
let a = 30; // SyntaxError: Identifier 'a' has already been declared

Обновление а let переменная разрешена. Однако, если вы попытаетесь повторно объявить его, вы столкнетесь с a SyntaxError. Это защищает разработчиков от тихого и случайного повторного объявления переменных.

Есть let переменные подняты?

Это сложный вопрос. Интернет разделился на этот счет: есть аргументы для обеих сторон. Некоторые разработчики считают, что letconst) переменные не поднимаются, потому что они не могут быть доступны до того, как будет достигнут их оператор объявления, в отличие от var. Однако этот ответ действительно зависит от вашего определения подъема. Если поднятие является соединением фаз объявления и инициализации переменной в верхней части соответствующей области действия, то let и const переменные не поднимаются.

Однако, прочитав несколько мнений и не будучи поближе к истине, я решил воспользоваться определением MDN подъема.

let Привязки создаются в верхней части области (блок), содержащей объявление, которое обычно называют «подъемом». (MDN)

Согласно этому определению, ответ на наш вопрос да. let переменные поднимаются, но они не инициализируются undefined. Таким образом, они существуют в период времени, который называется «Темпоральная мертвая зона» от начала блока до оценки их определения. Попытка получить доступ к ним в TDZ вызывает a ReferenceErrorкак видно на примере.

Ниже приведен пример, показывающий область блока let.

function outerFunc() {  let a = 10;  if (a > 5) {    let a = 20;    console.log(a); // 20  }  console.log(a); // 10}

Первое объявление переменной a находится в объеме outerFunc. The if блок создает новую область, а когда мы делаем второе объявление переменной a, он регистрируется в новой области Это не зависит от outerFunc объем. Итак, отдельная переменная a создается, и мы можем наблюдать, что меняется внутренняя переменная a не влияют на внешнюю переменную a.

Это позволяет разработчикам легко создавать временные переменные внутри блоков условий и циклов, без необходимости искать, переменная ли уже существует в функции.

конст

  1. область действия блока
  2. привязка неизменна (но значение может быть изменено или нет)
  3. не могут быть повторно объявлены
  4. поднято, но не инициализировано

Ниже приведен простой пример, когда мы инициализируем переменную, пытаемся обновить ее значение и пытаемся повторно объявить ее.

console.log(a); //  ReferenceError: a is not defined
const a = 10;console.log(a); // 10
a = 20; // TypeError: Assignment to constant variable.
const a = 30; // SyntaxError: Identifier 'a' has already been declared
const b; // SyntaxError: Missing initializer in const declaration

Похож на let переменные, const переменные поднимаются, но не инициализированы с undefined. Попытка получить доступ к ним в височной мертвой зоне вызывает a ReferenceError.

Если мы попытаемся инициализировать a const переменная без присвоения, как в приведенном выше примере for const b; мы встречаем a SyntaxError: Missing initializer in const declaration. Также мы не можем повторно декларировать const переменные. Это приводит к а SyntaxError.

Давайте временно приостановим наше обсуждение обновления const переменные.

Ниже приведен пример области действия на уровне блока const переменные:

function outerFunc() {  const a = 10;  if (a > 5) {    const a = 20;    console.log(a); // 20  }  console.log(a); // 10}

Вышеприведенное поведение похоже на let переменных, где создается новая область для if блок, а следовательно, изменения внутренней переменной a не влияют на внешнюю переменную a.

Вернемся к обсуждению обновления const переменные.

Это распространенное недоразумение const переменные имеют постоянные значения и никогда не могут быть обновлены. однако, const работает по другому.

После первоначального назначения в связывание с const переменные есть неизменный., а следовательно, в ссылка к тому, что хранится внутри const переменная не может быть изменена. Проще говоря, это означает, что вы не можете иметь заявление просто в const переменная в левой части, а затем знак равенства = и новое значение с правой стороны.

Однако то, можно ли обновить значение, зависит от того, что в нем сохраняется. Давайте рассмотрим два случая:

  1. Примитивный тип данных: Boolean, Null, Undefined, Number, String, Symbol
  2. Объекты

Если переменной присвоен примитивный тип данных, этот тип данных передается значение. Итак, если у нас есть заявление let x = 10 мы можем визуализировать x содержащий номер 10.

Если переменной присвоен объект, объект передается ссылка. Итак, если у нас есть заявление let x = [1,2,3], x не содержит массива [1,2,3] . Вместо этого он содержит ссылку (адрес) на то, где находится массив [1,2,3] хранится в памяти после его создания. Итак, мы можем визуализировать x содержит такой адрес, как 5274621.

Давайте посмотрим примеры примитивных и объектных типов данных:

// Booleanconst a = true;a = false; // TypeError: Assignment to constant variable.
// Nullconst b = null;b = 10; // TypeError: Assignment to constant variable.
// Undefinedconst c = undefined;c = 10; // TypeError: Assignment to constant variable.
// Numberconst d = 50;d = 100; // TypeError: Assignment to constant variable.
// Stringconst e="hello";e="world"; // TypeError: Assignment to constant variable.
// Symbolconst f = Symbol('foo');f = 100; // TypeError: Assignment to constant variable.

Как мы видим выше, попытка обновить значение любого примитивного типа данных приводит к a TypeError.

/* Arrays are stored by reference.Hence, although the binding is immutable, the values are not. */
const c = [1,2,3];
c.push(10); // No errorconsole.log(c); // [1,2,3,10]
c.pop(); // No errorconsole.log(c); // [1,2,3]
c = [4,5,6]; // TypeError: Assignment to constant variable.

Как мы видим выше, мы можем выталкивать и извлекать элементы из массива, поскольку это только изменяет содержание того, что const переменная указывает на, но не пытается перезаписать содержимое const самая переменная. Однако если мы попытаемся обновить привязку файла const переменной, повторно назначив ей совершенно новый массив c = [4,5,6]это бросает a TypeError.

/* Objects are stored by reference.Hence, although the binding is immutable, the values are not. */
const d = { name: 'John Doe', age: 35};
d.age = 40; // Modifying a property: No errorconsole.log(d); // { name: 'John Doe', age: 40};
d.zipCode="52534"; // Adding a property: No errorconsole.log(d); // { age: 40, name: "John Doe", zipCode: '52534; }
d = { name: 'Mary Jane', age: 25}; // TypeError: Assignment to constant variable.

Как мы видим выше, мы можем изменять и добавлять свойства к объекту, поскольку это изменяет только содержимое того, что const переменная указывает на, но не пытается перезаписать содержимое const самая переменная. Однако если мы попытаемся обновить привязку файла const переменной, повторно назначив ей совершенно новый объект d = { name: 'Mary Jane', age: 25 };это бросает a TypeError.

Когда я должен использовать что?

Теперь у JavaScript есть три вида переменных, и закономерный вопрос — когда использовать.

После внедрения блочной let использование var обычно не рекомендуется избегать путаницы с объемом уровня функций, случайных повторных деклараций и обнаружения ошибок с undefined значение. Если у вас нет веской причины использовать область функции varиспользуйте let.

Используйте const содержать ценности, являющиеся фактами, например const PI = 3.14или значения, которые должны строго оставаться неизменными на протяжении всего выполнения программы.

Обычный подход к программированию заключается в том, что разработчики начинают с объявления всех переменных с const и постепенно превращая их в let переменные, если возникнет необходимость. Лично я начну с let переменные и конвертировать их в const переменные, если я вижу потребность. Нет установленного подхода, и вы должны использовать то, что лучше всего подходит для вашего кода.

Если у вас есть время, я настоятельно предлагаю вам прочитать вымышленное произведение еще раз, поскольку оно укрепит связи в вашем сознании с дополнительными техническими знаниями.

Спасибо, что читаете! Надеюсь, вы узнали что-то новое, и я хотел бы получить отклик.

Следите за мной в Twitter здесь, а LinkedIn здесь.

Ссылки:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
  3. https://dmitripavlutin.com/variables-lifecycle-and-why-let-is-not-hoisted/
  4. https://github.com/getify/You-Dont-Know-JS

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *