Поиск по сайту:

Понимание переменных, области видимости и подъема в JavaScript


Введение

Переменные являются фундаментальной частью многих языков программирования и являются одними из первых и наиболее важных понятий, которые должны изучать начинающие программисты. В JavaScript есть ряд различных свойств переменных, а также несколько правил, которым необходимо следовать при их именовании. В JavaScript для объявления переменной используются три ключевых слова — var, let и const — и каждое из них влияет на интерпретацию кода. переменная по-разному.

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

Понимание переменных

Тип данных JavaScript, включая число, строку или объект.

До своего собственного раздела ниже.

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

// Assign the string value Sammy to the username identifier
var username = "sammy_shark";

Это заявление состоит из нескольких частей:

  • Объявление переменной с использованием ключевого слова var
  • Имя переменной (или идентификатор), имя пользователя
  • Операция присваивания, представленная синтаксисом =
  • Присваиваемое значение: sammy_shark

Теперь мы можем использовать username в коде. JavaScript запомнит, что username представляет строковое значение sammy_shark.

// Check if variable is equal to value
if (username === "sammy_shark") {
  console.log(true);
}
Output
true

Как упоминалось ранее, переменные могут использоваться для представления любого типа данных JavaScript. В этом примере мы объявим переменные со строковыми, числовыми, объектными, логическими и нулевыми значениями.

// Assignment of various variables
var name = "Sammy";
var spartans = 300;
var kingdoms = [ "mammals", "birds", "fish" ];
var poem = { roses: "red", violets: "blue" }; 
var success = true;
var nothing = null;

Используя console.log, мы можем увидеть значение, содержащееся в определенной переменной.

// Send spartans variable to the console
console.log(spartans);
Output
300

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

// Assign value to password variable
var password = "hunter2";

// Reassign variable value with a new value
password = "hunter3";

console.log(password);
Output
'hunter3'

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

Именование переменных

Имена переменных известны как идентификаторы в JavaScript. Мы обсудили несколько правил именования идентификаторов в разделе «Понимание синтаксиса и структуры кода в JavaScript», кратко изложенные здесь:

  • Имена переменных могут состоять только из букв (a–z), цифр (0–9), символов доллара ($) и подчеркивания (_)
  • Имена переменных не могут содержать пробельных символов (табуляции или пробелов)
  • Числа не могут начинаться с имени какой-либо переменной.
  • Есть несколько зарезервированных ключевых слов, которые нельзя использовать в качестве имени переменной.
  • Имена переменных вводятся с учетом регистра

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

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

Разница между var, let и const

В JavaScript есть три разных ключевых слова для объявления переменной, что добавляет дополнительный уровень сложности языку. Различия между ними основаны на объеме, подъеме и переназначении.

Keyword Scope Hoisting Can Be Reassigned Can Be Redeclared
var Function scope Yes Yes Yes
let Block scope No Yes No
const Block scope No No No

Вам может быть интересно, какой из трех вы должны использовать в своих собственных программах. Общепринятой практикой является максимальное использование const и let в случае циклов и переназначения. Как правило, var можно не использовать вне работы с унаследованным кодом.

Область действия переменной

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

  • Глобальные переменные — это переменные, объявленные вне блока.
  • Локальные переменные – это переменные, объявленные внутри блока.

В приведенном ниже примере мы создадим глобальную переменную.

// Initialize a global variable
var creature = "wolf";

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

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

// Initialize a global variable
var species = "human";
 
function transform() {
  // Initialize a local, function-scoped variable
  var species = "werewolf";
  console.log(species);
}

// Log the global and local variable
console.log(species);
transform();
console.log(species);
Output
human werewolf human

В этом примере локальная переменная находится в области действия. Переменные, объявленные с помощью ключевого слова var, всегда относятся к области действия функции, то есть они распознают функции как имеющие отдельную область действия. Таким образом, эта переменная с локальной областью недоступна из глобальной области.

Однако новые ключевые слова let и const имеют блочную область действия. Это означает, что новая локальная область действия создается из блоков любого типа, включая функциональные блоки, операторы if и циклы for и while.

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

var fullMoon = true;

// Initialize a global variable
let species = "human";

if (fullMoon) {
  // Initialize a block-scoped variable
  let species = "werewolf";
  console.log(`It is a full moon. Lupin is currently a ${species}.`);
}

console.log(`It is not a full moon. Lupin is currently a ${species}.`);
Output
It is a full moon. Lupin is currently a werewolf. It is not a full moon. Lupin is currently a human.

В этом примере переменная species имеет одно глобальное значение (human) и другое локальное значение (werewolf). Однако если бы мы использовали var, результат был бы другим.

// Use var to initialize a variable
var species = "human";

if (fullMoon) {
  // Attempt to create a new variable in a block
  var species = "werewolf";
  console.log(`It is a full moon. Lupin is currently a ${species}.`);
}

console.log(`It is not a full moon. Lupin is currently a ${species}.`);
Output
It is a full moon. Lupin is currently a werewolf. It is not a full moon. Lupin is currently a werewolf.

В результате этого примера и глобальная переменная, и переменная блочной области действия получают одно и то же значение werewolf. Это связано с тем, что вместо создания новой локальной переменной с помощью var вы переназначаете ту же переменную в той же области. var не распознает if как часть другой, новой области. Обычно рекомендуется объявлять переменные с блочной областью действия, поскольку они создают код, который с меньшей вероятностью непреднамеренно переопределит значения переменных.

Подъем

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

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

// Attempt to use a variable before declaring it
console.log(x);

// Variable assignment
var x = 100;
Output
undefined

Однако, если мы опускаем ключевое слово var, мы больше не объявляем переменную, а только инициализируем ее. Он вернет ReferenceError и остановит выполнение скрипта.

// Attempt to use a variable before declaring it
console.log(x);

// Variable assignment without var
x = 100;
Output
ReferenceError: x is not defined

Причина этого связана с подъемом, поведением JavaScript, при котором объявления переменных и функций перемещаются в верхнюю часть их области видимости. Поскольку поднимается только фактическое объявление, а не инициализация, значение в первом примере возвращает undefined.

Чтобы продемонстрировать эту концепцию более четко, ниже приведен код, который мы написали, и то, как JavaScript фактически интерпретировал его.

// The code we wrote
console.log(x);
var x = 100;

// How JavaScript interpreted it
var x;
console.log(x);
x = 100;

JavaScript сохранил x в памяти как переменную перед выполнением скрипта. Поскольку он все еще вызывался до того, как был определен, результатом будет undefined, а не 100. Однако это не вызывает ReferenceError и не останавливает скрипт. Хотя ключевое слово var на самом деле не изменило местоположение var, это полезное представление о том, как работает подъем. Однако такое поведение может вызвать проблемы, потому что программист, написавший этот код, вероятно, ожидает, что вывод x будет 100, хотя вместо этого undefined.

Мы также можем увидеть, как подъем может привести к непредсказуемым результатам в следующем примере:

// Initialize x in the global scope
var x = 100;

function hoist() {
  // A condition that should not affect the outcome of the code
  if (false) {
    var x = 200;
  }
  console.log(x);
}

hoist();
Output
undefined

В этом примере мы объявили x равным 100 глобально. В зависимости от оператора if x может измениться на 200, но поскольку условие было false, оно не должно было повлияло на значение x. Вместо этого x был поднят наверх функции hoist(), и значение стало undefined.

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

// Initialize x in the global scope
let x = true;

function hoist() {
  // Initialize x in the function scope
  if (3 === 4) {
    let x = false;
  }
  console.log(x);
}

hoist();
Output
true

Повторное объявление переменных, которое возможно с помощью var, вызовет ошибку с помощью let и const.

// Attempt to overwrite a variable declared with var
var x = 1;
var x = 2;

console.log(x);
Output
2
// Attempt to overwrite a variable declared with let
let y = 1;
let y = 2;

console.log(y);
Output
Uncaught SyntaxError: Identifier 'y' has already been declared

Подводя итог, можно сказать, что переменные, представленные с помощью var, потенциально могут подвергаться воздействию подъема — механизма в JavaScript, в котором объявления переменных сохраняются в памяти. Это может привести к неопределенным переменным в коде. Введение let и const решает эту проблему, выдавая ошибку при попытке использовать переменную перед ее объявлением или при попытке объявить переменную более одного раза.

Константы

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

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

В приведенном ниже примере мы инициализируем переменную SPECIES как константу с помощью ключевого слова const. Попытка переназначить переменную приведет к ошибке.

// Assign value to const
const SPECIES = "human"; 

// Attempt to reassign value
SPECIES = "werewolf";

console.log(SPECIES);
Output
Uncaught TypeError: Assignment to constant variable.

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

// Declare but do not initialize a const
const TODO;

console.log(TODO);
Output
Uncaught SyntaxError: Missing initializer in const declaration

Значения, которые нельзя изменить в программировании, называются неизменяемыми, а значения, которые можно изменить, называются изменяемыми. Хотя значения const нельзя переназначить, они изменяемы, поскольку можно изменить свойства объектов, объявленных с помощью const.

// Create a CAR object with two properties
const CAR = {
	color: "blue",
	price: 15000
}

// Modify a property of CAR
CAR.price = 20000;

console.log(CAR);
Output
{ color: 'blue', price: 20000 }

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

Заключение

В этом руководстве мы рассмотрели, что такое переменная, правила именования переменных и способы переназначения значений переменных. Мы также узнали об области действия и подъеме, некоторых ограничениях исходного ключевого слова var, а также о том, как let и const решают эти проблемы.

Чтобы сравнить, как переменные используются в других языках, вы можете прочитать наш учебник «Как использовать переменные в Python 3».