Переменные

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

Имя переменной называется идентификатором . Действительный идентификатор должен соответствовать следующим правилам:

  • Идентификаторы могут содержать буквы Юникода, знаки доллара ($), символы подчеркивания (_), цифры (0–9) и даже некоторые символы Юникода.
  • Идентификаторы не могут содержать пробелы, поскольку анализатор использует пробелы для разделения входных элементов. Например, если вы попытаетесь вызвать переменную my Variable вместо myVariable , анализатор увидит два идентификатора, my и Variable , и выдаст синтаксическую ошибку («неожиданный токен: идентификатор»).
  • Идентификаторы должны начинаться с буквы, подчеркивания ( _ ) или знака доллара ( $ ). Они не могут начинаться с цифр, чтобы избежать путаницы между числами и идентификаторами:

    let 1a = true;
    
    > Uncaught SyntaxError: Invalid or unexpected token
    

    Если бы JavaScript допускал использование чисел в начале идентификатора, это позволило бы использовать идентификаторы, состоящие только из чисел, что вызывало бы конфликты между числами, используемыми в качестве чисел, и числами, используемыми в качестве идентификаторов:

    let 10 = 20
    
    10 + 5
    > ?
    
  • « Зарезервированные слова », которые уже имеют синтаксическое значение, не могут использоваться в качестве идентификаторов.

  • Идентификаторы не могут содержать специальные символы ( ! . , / \ + - * = ).

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

Следуя примеру встроенных методов и свойств JavaScript, верблюжий регистр (также стилизованный как «camelCase») является очень распространенным соглашением для идентификаторов, состоящих из нескольких слов. Верблюжий регистр — это практика использования заглавной буквы каждого слова, кроме первой, для улучшения читаемости без пробелов.

let camelCasedIdentifier = true;

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

class MyClass {

}

Идентификаторы должны кратко описывать характер содержащихся в них данных (например, currentMonthDays — лучшее имя, чем theNumberOfDaysInTheCurrentMonth ) и легко читаться с первого взгляда ( originalValue лучше, чем val ). Идентификаторы myVariable , используемые в этом модуле, работают в контексте отдельных примеров, но будут очень бесполезны в рабочем коде, поскольку они не дают информации о том, какие данные они содержат.

Идентификаторы не должны быть слишком конкретными в отношении содержащихся в них данных, поскольку их значения могут меняться в зависимости от того, как сценарии действуют с этими данными, или от решений, которые примут будущие сопровождающие. Например, переменную, первоначально имеющую идентификатор miles возможно, потребуется изменить на значение в километрах позже в проекте, что потребует от сопровождающих изменить любые ссылки на эту переменную, чтобы избежать путаницы в будущем. Чтобы предотвратить это, вместо этого используйте distance в качестве идентификатора.

JavaScript не дает каких-либо особых привилегий или значения идентификаторам, которые начинаются с символов подчеркивания ( _ ), но они обычно используются, чтобы показать, что переменная, метод или свойство являются «частными», то есть предназначены для использования только внутри контекст объекта, который его содержит, и к нему нельзя обращаться или изменять вне этого контекста. Это соглашение перенесено из других языков программирования и появилось до добавления частных свойств в JavaScript.

Объявление переменной

Существует несколько способов сообщить JavaScript об идентификаторе. Этот процесс называется «объявлением» переменной. Переменная объявляется с использованием ключевых слов let , const или var .

let myVariable;

Используйте let или var , чтобы объявить переменную, которую можно изменить в любое время. Эти ключевые слова сообщают интерпретатору JavaScript, что строка символов является идентификатором, который может содержать значение.

При работе с современной кодовой базой используйте let вместо var . var по-прежнему работает в современных браузерах, но имеет некоторые неинтуитивное поведение, которое было определено в самых ранних версиях JavaScript и не могло быть изменено позже для сохранения обратной совместимости. let был добавлен в ES6 для решения некоторых проблем с дизайном var .

Объявленная переменная инициализируется путем присвоения переменной значения. Используйте одиночный знак равенства ( = ), чтобы присвоить или переназначить значение переменной. Вы можете сделать это как часть того же оператора, который это объявляет:

let myVariable = 5;

myVariable + myVariable
> 10

Вы также можете объявить переменную с помощью let (или var ) без ее немедленной инициализации. Если вы это сделаете, начальное значение переменной будет undefined , пока ваш код не присвоит ей значение.

let myVariable;

myVariable;
> undefined

myVariable = 5;

myVariable + myVariable
> 10

Переменная с undefined значением отличается от неопределенной переменной, идентификатор которой еще не объявлен. Ссылка на переменную, которую вы не объявили, приводит к ошибке.

myVariable
> Uncaught ReferenceError: myVariable is not defined

let myVariable;

myVariable
> undefined

Ассоциация идентификатора со значением обычно называется «привязкой». Синтаксис, следующий за ключевыми словами let , var или const , называется «списком привязки» и допускает несколько объявлений переменных, разделенных запятыми (заканчивающихся ожидаемой точкой с запятой). Это делает следующие фрагменты кода функционально идентичными:

let firstVariable,
     secondVariable,
     thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;

При переназначении значения переменной не используется let (или var ), поскольку JavaScript уже знает, что переменная существует:

let myVariable = true;

myVariable
> true

myVariable = false;

myVariable
> false

Вы можете переназначать переменным новые значения на основе их существующих значений:

let myVariable = 10;

myVariable
> 10

myVariable = myVariable * myVariable;

myVariable
> 100

Если вы попытаетесь переопределить переменную с помощью let в производственной среде, вы получите синтаксическую ошибку:

let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable

Инструменты разработчика браузеров более терпимы к повторному объявлению letclass ), поэтому вы можете не увидеть ту же ошибку в консоли разработчика.

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

var myVariable = true;
var myVariable = false;

myVariable\
> false

const

Используйте ключевое слово const для объявления константы — типа переменной, которая должна быть немедленно инициализирована и затем не может быть изменена. Идентификаторы констант подчиняются тем же правилам, что и переменные, объявленные с помощью letvar ):

const myConstant = true;

myConstant
> true

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

const myConstant;
Uncaught SyntaxError: missing = in const declaration

Попытка изменить значение переменной, объявленной с помощью const так же, как вы могли бы изменить значение переменной, объявленной с помощью let (или var ), приводит к ошибке типа:

const myConstant = true;

myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'

Однако когда константа связана с объектом, свойства этого объекта могут быть изменены.

const constantObject = { "firstvalue" : true };

constantObject
> Object { firstvalue: true }

constantObject.secondvalue = false;

constantObject
> Object { firstvalue: true, secondvalue: false }

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

const constantObject = { "firstvalue" : true };

constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'

Если вы не ожидаете переназначения переменной, лучше всего сделать ее константой. Использование const сообщает вашей команде разработчиков или будущим сопровождающим проекта не изменять это значение, чтобы не нарушить предположения, которые ваш код делает о том, как оно используется — например, что переменная в конечном итоге будет оцениваться по ожидаемому типу данных.

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

Область видимости переменной — это часть скрипта, в которой эта переменная доступна. За пределами области действия переменной она не будет определена — не как идентификатор, содержащий undefined значение, а как если бы она не была объявлена.

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

Область действия блока

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

{
    let scopedVariable = true;
    console.log( scopedVariable );
}
> true

scopedVariable
> ReferenceError: scopedVariable is not defined

Что касается JavaScript, переменная области действия блока не существует вне блока, который ее содержит. Например, вы можете объявить константу внутри блока, а затем объявить другую константу вне этого блока, использующую тот же идентификатор:

{
  const myConstant = false;
}
const myConstant = true;

scopedConstant;
> true

Хотя объявленная переменная не может распространяться на родительский блок, она доступна всем блокам-потомкам:

{
    let scopedVariable = true;
    {
    console.log( scopedVariable );
    }
}
> true

Значение объявленной переменной можно изменить изнутри блока-потомка:

{
    let scopedVariable = false;
    {
    scopedVariable = true;
    }
    console.log( scopedVariable );
}
> true

Новую переменную можно инициализировать с помощью let или const внутри блока-потомка без ошибок, даже если она использует тот же идентификатор, что и переменная в родительском блоке:

{
    let scopedVariable = false;
    {
    let scopedVariable = true;
    }
    console.log( scopedVariable );
}
> false

Область применения функции

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

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

Это по-прежнему имеет место после вызова функции. Несмотря на то, что переменная инициализируется во время выполнения функции, она по-прежнему недоступна вне области действия функции:

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

myFunction();
> true

scopedVariable;
> ReferenceError: scopedVariable is not defined

Глобальная область действия

Глобальная переменная доступна во всем приложении JavaScript, внутри любых блоков и функций, в любом скрипте на странице.

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

Любая переменная, объявленная с помощью var вне родительской функции или с помощью let или const вне родительского блока, является глобальной:

var functionGlobal = true; // Global
let blockGlobal = true; // Global

{
    console.log( blockGlobal );
    console.log( functionGlobal );
}
> true
> true

(function() {
    console.log( blockGlobal );
    console.log( functionGlobal );
}());
> true
> true

Присвоение значения переменной без его явного объявления (то есть никогда не используя var , let или const для ее создания) поднимает переменную до глобальной области видимости, даже если она инициализируется внутри функции или блока. Переменную, созданную с использованием этого шаблона, иногда называют «подразумеваемой глобальной».

function myFunction() {
    globalVariable = "global";

    return globalVariable
}

myFunction()\
> "global"

globalVariable\
> "global"

Переменный подъем

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

hoistedVariable
> undefined

var hoistedVariable;

Поскольку размещается только объявление переменной, а не инициализация, переменные, которые не были явно объявлены с помощью var , let или const , не поднимаются:

unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined

unhoistedVariable = true;

Как упоминалось ранее , объявленной, но неинициализированной переменной присваивается значение undefined . Такое поведение применимо и к объявлениям поднятых переменных, но только к тем, которые объявлены с использованием var .

hoistedVariable
> undefined

var hoistedVariable = 2 + 2;

hoistedVariable\
> 4

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

let и const решают эту проблему, вместо этого выдавая ошибку при доступе к переменной до ее создания:

{
    hoistedVariable;

    let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization

Эта ошибка отличается от ошибки «hoistedVariable не определена», которую можно ожидать при попытке доступа к необъявленной переменной. Поскольку JavaScript поднял переменную, он знает, что переменная будет создана в заданной области. Однако вместо того, чтобы сделать эту переменную доступной до ее объявления со значением undefined , интерпретатор выдает ошибку. Говорят, что переменные, объявленные с помощью let или const (или class ), существуют во «временной мертвой зоне» («TDZ») от начала охватывающего их блока до момента объявления переменной.

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

Проверьте свое понимание

С каких символов можно начинать идентификатор?

Письмо
Подчеркивание
цифра

Какой метод объявления переменной, значение которой можно изменить в любой момент, предпочтительнее?

позволять
константа
вар