Variables

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

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

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

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

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

Имя переменной

Вы можете использовать переменные как символические имена для значений в вашем приложении. Имена переменных называются identifiers и должны соответствовать определенным правилам.

Идентификатор в JavaScript должен начинаться с буквы, нижнего подчеркивания (_) или знака доллара ($); последующие символы могут также быть цифрами (0-9). Поскольку JavaScript чувствителен к регистру, буквы включают символы от "A" до "Z" (верхний регистр) и символы от "a" до "z" (нижний регистр).

Вы можете использовать в идентификаторах буквы ISO 8859-1 или Unicode, например, å или ü. Вы также можете использовать управляющие последовательности Unicode как символы в идентификаторах.

В общем-то, те же правила, применяемые к идентификатору переменной, применяются и к имени свойства. Однако определенные слова не используются как переменные, но могут использоваться как имена свойств. Эти слова называются "зарезервированными словами" и включают ключевые слова JS (for,in,ifи т.д.), включая иnull,trueиfalse.

Некоторые примеры корректных имен: Number_hits, temp99, _name.

Рекомендации по именования переменных

Вы можете назвать переменную как угодно, но есть ограничения. Как правило, вы должны придерживаться только латинских символов (0-9, a-z, A-Z) и символа подчеркивания.

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

  • Не используйте числа в начале переменных. Это недопустимо и приведет к ошибке.

  • Общепринято придерживаться так называемого "lower camel case", где вы склеиваете несколько слов, используя строчные буквы для целого первого слова, а затем заглавные буквы следующих слов. Мы использовали для наших имен переменные в данной статье.

  • Делайте имена переменных такими, чтобы было интуитивно понятно, какие данные они содержат. Не используйте только отдельные буквы / цифры или большие длинные фразы.

Объявление переменных

В JavaScript существует три вида объявлений переменных:

var - Объявляет переменную, инициализация переменной значением является необязательной.

let - Объявляет локальную переменную в области видимости блока, инициализация переменной значением является необязательной.

const - Объявляет именованную константу, доступную только для чтения.

Переменные можно объявить следующими способами:

  • Используя ключевое слово var. Например, var x = 42. Данный синтаксис может быть использован для объявления как локальных, так и глобальных переменных.

  • Просто присвоить переменной значение. Например, x = 42. Переменные, объявленные данным способом, являются глобальными. Такое объявление генерирует строгое предупреждение (strict mode). Не рекомендуется использовать данный способ.

  • Используя ключевое слово let. Например, let y = 13. Данный синтаксис может быть использован для объявления локальной переменной в области видимости блока.

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

"use strict";
mistypedVaraible = 17; // выдаст ReferenceError

Присваивание переменных

Переменная, объявленная через var или let без присвоения начального значения, имеет значение undefined. При попытке доступа к необъявленной переменной или переменной до её объявления будет выброшено исключение ReferenceError:​

var a;
console.log("The value of a is " + a); //Значение переменной a undefined

console.log("The value of b is " + b); //Uncaught ReferenceError: b не определена

console.log("The value of c is " + c); //Значение переменной c undefined
var c;

console.log("The value of x is " + x); //Uncaught ReferenceError: x не определена
let x;

Когда переменной присваивается значение, вы можете изменить (обновить) это значение, просто указав другое значение. Попробуйте ввести следующие строки в консоль:

myName = 'Bob';
myAge = 40;

Cтрогий режим заставляет присваивания, которые все равно завершились бы неудачей, выбрасывать исключения. Например, NaN -- глобальная переменная, защищенная от записи. В обычном режиме присваивание NaN-значения ничего не делает; разработчик не получает никакого сообщения об ошибке. В строгом режиме присваивание значения NaN выбрасывает исключение. Любое присваивание, которое в обычном режиме завершается неудачей (присваивание значения свойству, защищенному от записи; присваивание значения свойству, доступному только для чтения; присваивание нового свойства нерасширяемому объекту) в строгом режиме выбросит исключение:

"use strict";

// Присвоение non-writable свойства
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // выдаст TypeError

// Присвоение getter-only свойства
var obj2 = { get x() { return 17; } };
obj2.x = 5; // выдаст TypeError

// Присвоение нового свойства non-extensible объекту
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // выдаст TypeError

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

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

До ECMAScript 6 в JavaScript отсутствовала область видимости блока; переменная, объявленная внутри блока, является локальной для функции (или глобальной области видимости), внутри которой находится данный блок. Например, следующий код выведет значение 5, т.к. областью видимости переменной x является функция (или глобальный контекст), внутри которой объявлена переменная x, а не блок, которым в данном случае является оператор if:

if (true) {
  var x = 5;
}
console.log(x); // 5

Такое поведение меняется, если используется операторlet, введенный в ECMAScript 6:

if (true) {
  let y = 5;
}
console.log(y); // ReferenceError

Поднятие переменных

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

Где бы ни появлялось var внутри области видимости, это объявление принадлежит всей области видимости и доступно в ней повсюду.

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

Пример:

var a = 2;

foo();                    // работает, так как определение `foo()`
                        // "всплыло"

function foo() {
    a = 3;

    console.log( a );    // 3

    var a;                // определение "всплыло"
                        // наверх `foo()`
}

console.log( a );    // 2

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

Вложенные области видимости

Когда вы объявляете переменную, она доступна повсюду в области ее видимости так же, как и в более нижних/внутренних областях видимости. Например:

function foo() {
    var a = 1;

    function bar() {
        var b = 2;

        function baz() {
            var c = 3;

            console.log( a, b, c );    // 1 2 3
        }

        baz();
        console.log( a, b );        // 1 2
    }

    bar();
    console.log( a );                // 1
}

foo();

Заметьте, чтоcнедоступна внутри bar(), потому что она объявлена только внутри внутренней области видимостиbaz()иbнедоступна вfoo()по той же причине.

Если вы попытаетесь получить доступ к значению переменной в области видимости, где она уже недоступна, вы получите ReferenceError. Если вы попытаетесь установить значение переменной, которая еще не объявлена, у вас закончится все тем, что переменная создастся в самой верхней глобальной области видимости (плохо!), либо получите ошибку в зависимости от "строгого режима" (см. "Строгий режим"). Давайте посмотрим:

function foo() {
    a = 1;    // `a` формально не объявлена
}

foo();
a;            // 11

Это очень плохая практика. Не делайте так! Всегда явно объявляйте свои переменные.

В дополнение к созданию объявлений переменных на уровне функций, ES6 позволяет вам объявлять переменные, принадлежащие отдельным блокам (пара{ .. }), используя ключевое слово let. Кроме некоторых едва уловимых деталей, правила области видимости будут вести себя точно так же, как мы видели в функциях:

function foo() {
    var a = 1;

    if (a >= 1) {
        let b = 2;

        while (b < 5) {
            let c = b * 2;
            b++;

            console.log( a + c );
        }
    }
}

foo();
// 5 7 9

Из-за использования let вместо var,b будет принадлежать только оператору if и, следовательно, не всей области видимости функции foo(). Точно так же c принадлежит только циклу while. Блочная область видимости очень полезна для управления областями ваших переменных более точно, что может сделать ваш код более легким в обслуживании в долгосрочной перспективе.

Источники:

Last updated