Modern JS Cheatsheet / Памятка по современному JavaScript: Объявление переменных

Английский оригинал Перевод на русский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

### Объявление переменных: var, const, let

Tomatoknight 27.09.17 в 13:45

0

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

Tomatoknight 27.09.17 в 13:45

0

#### Краткое объяснение

Tomatoknight 27.09.17 в 13:45

0

Переменные, объявленные при помощи ключевого слова "const", нельзя переопределить. "Let" и "var" - можно.

Tomatoknight 27.09.17 в 13:48

0

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

a_popova 02.10.17 в 14:35

1

Я рекомендую всегда объявлять переменные ключевым словом "const", а "let" использовать только в том случае, если позже эту переменную понадобится *изменить* или переопределить.

Tomatoknight 27.09.17 в 13:50

1

Я рекомендую всегда объявлять все переменные по умолчанию с помощью ```const```, а те, которые можно нужно будет *изменить* или передопределить, с помощью ```let```.

a_popova 02.10.17 в 14:36

0

<table>
<tr>
<th></th>
<th>Область видимости</th>
<th>Можно переопределять</th>
<th>Можно изменять</th>
<th><a href="#tdz_sample">Временная мертвая зона</a></th>
</tr>
<tr>
<th>const</th>
<td>Блок</td>
<td>Нет</td>
<td><a href="#const_mutable_sample">Да</a></td>
<td>Да</td>
</tr>
<tr>
<th>let</th>
<td>Блок</td>
<td>Да</td>
<td>Да</td>
<td>Да</td>
</tr>
<tr>
<th>var</th>
<td>Функция</td>
<td>Да</td>
<td>Да</td>
<td>Нет</td>
</tr>
</table>

Tomatoknight 27.09.17 в 13:56

0

#### Пример кода

Tomatoknight 27.09.17 в 13:56

0

```javascript
const person = "Коля";
person = "Ваня" // Ошибка: переопределять переменную person нельзя.
```

Tomatoknight 27.09.17 в 13:57

0

Вызовет ошибку, переменной "person" нельзя присвоить новое значение

a_popova 02.10.17 в 14:37

0

```javascript
let person = "Коля";
person = "Ваня";
console.log(person) // "Ваня", с let переменную можно переопределить.
```

Tomatoknight 27.09.17 в 13:58

0

присвоение нового значения разрешено в случае с let

a_popova 02.10.17 в 14:38

0

#### Подробное объяснение

Tomatoknight 27.09.17 в 13:58

0

[*Область видимости*](#scope_def) переменной определяет, где эта переменная доступна в коде.

a_popova 02.10.17 в 14:39

0

##### var

Tomatoknight 27.09.17 в 13:59

0

Переменные, объявленные словом "var", имеют *область видимости на уровне функций*. Это значит, что, когда в функции создается переменная, то всё, что внутри этой функции, имеет к этой переменной доступ. И если у переменной *область видимости на уровне функций*, то доступа извне этой функции к этой переменной нет.

Tomatoknight 27.09.17 в 14:06

0

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

a_popova 02.10.17 в 14:43

1

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

Tomatoknight 27.09.17 в 14:08

1

Я рекомендую представлять это как будто переменная с областью видимости X означает, что эта переменная является свойством X.

a_popova 02.10.17 в 14:44

0

```javascript
function myFunction() {
var myVar = "Коля";
console.log(myVar); // "Коля" - к myVar есть доступ изнутри функции
}
console.log(myVar); // Undefined, извне доступа к myVar нет.
```

Tomatoknight 27.09.17 в 14:09

0

Вот несколько менее очевидный пример области видимости переменных:

Tomatoknight 27.09.17 в 14:10

0

```javascript
function myFunction() {
var myVar = "Коля";
if (true) {
var myVar = "Ваня";
console.log(myVar); // "Ваня"
// Поскольку область видимости myVar на уровне функции, здесь мы просто стерли предыдущее значение myVar - "Коля" - и заменили его на "Ваня".
}
console.log(myVar); // "Ваня" - видите, инструкции в блоке if повлияли на значение переменной.
}
console.log(myVar); // Undefined, доступа к myVar извне функции нет.
```

Tomatoknight 27.09.17 в 14:13

0

// действительно, myVar имеет область видимости внутри функции, мы всего лишь удалили предыдущее значение переменной myVar "Nick" и заменили его на "John"
// "John" - обратите внимание, как код в блоке "if" повлиял на это значение
// Выдаст ошибку, переменная myVar недоступна за пределами функции, в которой определена

a_popova 09.10.17 в 14:03

0

Кроме этого, переменные, объявленные ключевым словом *var*, при исполнении кода перемещаются в начало области видимости. Это называется [поднятие переменных](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/var#Поднятие_переменных).

Tomatoknight 27.09.17 в 14:17

0

Этот фрагмент кода:

a_popova 02.10.17 в 14:45

0

```js
console.log(myVar) // undefined -- ошибок нет
var myVar = 2;
```

Tomatoknight 27.09.17 в 14:18

0

при исполнении понимается как:

Tomatoknight 27.09.17 в 14:18

0

```js
var myVar;
console.log(myVar) // undefined -- ошибок нет
myVar = 2;
```

Tomatoknight 27.09.17 в 14:18

0

##### let

Tomatoknight 27.09.17 в 14:19

0

```var``` и ```let``` очень похожи друг на друга, но переменные, объявленные словом ```let```:

Tomatoknight 27.09.17 в 14:19

0

- имеют *блоковую область видимости*
- **недоступны** до объявления
- в пределах одной области видимости их можно объявить только один раз

Tomatoknight 27.09.17 в 14:21

0

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

a_popova 02.10.17 в 14:45

0

- имеют в качестве области видимости блок
- **недоступны** до объявления
- не могут быть повторно объявлены в той же области видимости

wizjer 11.10.17 в 05:47

1
+2

Давайте разберем, насколько важна блоковая область видимости, на том же самом примере:

Tomatoknight 27.09.17 в 14:21

0

```javascript
function myFunction() {
let myVar = "Коля";
if (true) {
let myVar = "Ваня";
console.log(myVar); // "Ваня"
// Поскольку myVar имеет блоковую область видимости, здесь мы только что создали новую переменную myVar.
// Эта переменная недоступна вне блока и никаким образом не зависит
// от первой переменной myVar, которую мы создали до этого!
}
console.log(myVar); // "Коля" - видите, инструкции в блоке if НЕ повлияли на значение переменной
}
console.log(myVar); // Undefined, доступа к myVar извне функции нет.
```

Tomatoknight 27.09.17 в 14:24

0

<a name="tdz_sample"></a> Теперь посмотрим, что значит "переменные, объявленные словами "let" и "const", недоступны до их объявления":

Tomatoknight 27.09.17 в 14:26

1

<a name="tdz_sample"></a> Теперь рассмотрим, что означает тот факт, что переменные, объявленные с помощью *let* (и *const*) недоступны до того, как им присвоены значения:

a_popova 02.10.17 в 14:46

0

```js
console.log(myVar) // вызывает ReferenceError !
let myVar = 2;
```

Tomatoknight 27.09.17 в 14:27

0

В отличие от переменных *var*, если попытаться прочитать или записать переменную *let* или *const* до того, как они объявлены, выбрасывается ошибка. Этот феномен часто называется [*временной мертвой зоной*](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let#Временные_мертвые_зоны_и_ошибки_при_использовании_let), или *ВМЗ*.

Tomatoknight 27.09.17 в 14:30

0

В отличие от переменных, объявленных с помощью *var*, если вы попытаетесь прочитать или записать переменную, объявленную с помощью *let* или *const*, до того, как ей будет присвоено значение, произойдёт ошибка. Этот феномен часто называют [*Временной мёртвой зоной*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let).

a_popova 02.10.17 в 14:47

1

**Примечание:** строго говоря, переменные *let* и *const* тоже поднимаются, но их объявление - нет. Они сделаны так, что использовать их до объявления нельзя. Поэтому интуитивно ощущается так, будто эти переменные не поднимаются - но это не так. Если интересно, детали можно узнать в [этом очень подробном объяснении](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified).

Tomatoknight 27.09.17 в 14:33

0

> **Примечание:**: Технически объявления переменных с использованием *let* и *const* тоже поднимаются, однако их присваивания - нет. Хотя это сделано для того, чтобы переменные нельзя было использовать до присвоения им значений, интуитивно кажется, что подъёма нет, но он есть. Ищите больше информации в [этом очень подробном объяснении](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified), если хотите знать больше.

a_popova 02.10.17 в 14:47

0

**Примечание:** строго говоря, объявления переменных с использованием *let* и *const* тоже поднимаются, однако их инициализация — нет. Они сделаны так, что использовать их до объявления нельзя. Поэтому интуитивно ощущается так, будто эти переменные не поднимаются — но это не так. Ищите больше информации в [этом очень подробном объяснении](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified), если хотите знать больше.

wizjer 11.10.17 в 05:56

1
+1

Кроме того, переменную *let* нельзя объявлять несколько раз:

Tomatoknight 27.09.17 в 14:33

0

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

a_popova 09.10.17 в 14:38

1

```js
let myVar = 2;
let myVar = 3; // Вызывает SyntaxError
```

Tomatoknight 27.09.17 в 14:34

0

##### const

Tomatoknight 27.09.17 в 14:34

0

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

Tomatoknight 27.09.17 в 14:35

1

Переменные, объявленные с помощью ```const```, ведут себя так же, как переменные, объявленные с помощью *let*, но также им не может быть присвоено новое значение.

a_popova 02.10.17 в 14:48

0

То есть, переменные *const*:

Tomatoknight 27.09.17 в 14:35

0

Подводя итог, переменные объявленные с помощью *const*:

a_popova 02.10.17 в 14:49

1

- имеют *блочную область видимости*
- недоступны до объявления
- не могут быть объявлены несколько раз
- не могут быть переопределены

Tomatoknight 27.09.17 в 14:36

0

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

a_popova 02.10.17 в 14:49

0

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

wizjer 11.10.17 в 05:58

0

```js
const myVar = "Коля";
myVar = "Ваня" // вызывает ошибку, переопределять переменную нельзя.
```

Tomatoknight 27.09.17 в 14:36

0

```js
const myVar = "Коля";
const myVar = "Ваня" // вызывает ошибку, объявить переменную можно только один раз.
```

Tomatoknight 27.09.17 в 14:37

0

<a name="const_mutable_sample"></a> Но есть нюанс: переменные "const" можно [**изменять**](#mutation_def) ! Если точнее, это значит, что **можно** изменять *объекты* и *массивы* в переменных *const*.

Tomatoknight 27.09.17 в 14:39

0

<a name="const_mutable_sample"></a> Но есть одна тонкость: переменные, объявленные с помощью ```const```не являются [**неизменными**](#mutation_def) ! Конкретно это означает, что *объекты* и *массивы*, объявленные с помощью ```const```, **могут** быть изменены. .

a_popova 02.10.17 в 14:49

1

В случае объектов:
```js
const person = {
name: 'Коля'
};
person.name = 'Ваня' // сработает! Переменная person не полностью переопределяется, а просто меняется
console.log(person.name) // "Ваня"
person = "Сандра" // вызывает ошибку, потому что переменные, объявленные словом "const", переопределять нельзя
```

Tomatoknight 27.09.17 в 14:40

1

Для объектов:
```js
const person = {
name: 'Nick'
};
person.name = 'John' // это сработает ! переменной person не назначено новое значение, но значение изменено
console.log(person.name) // "John"
person = "Sandra" // вызовет ошибку, т.к. задание нового значения не разрешено для переменных, объявленных с помощью const
```

a_popova 09.10.17 в 15:11

0

В случае массивов:
```js
const person = [];
person.push('Ваня'); // сработает! Переменная person не полностью переопределяется, а просто меняется
console.log(person[0]) // "Ваня"
person = ["Коля"] // вызывает ошибку, потому что переменные, объявленные словом "const", переопределять нельзя
```

Tomatoknight 27.09.17 в 14:41

1

Для массивов:
```js
const person = [];
person.push('John'); // это сработает ! переменной person не назначено новое значение, но значение изменено
console.log(person[0]) // "John"
person = ["Nick"] // вызовет ошибку, т.к. задание нового значения не разрешено для переменных, объявленных с помощью const
```

a_popova 09.10.17 в 15:08

0

#### Внешние ресурсы

Tomatoknight 27.09.17 в 14:41

0

- [Область видимости let и const в JavaScript - WesBos](http://wesbos.com/javascript-scoping/)
- [Демистификация временной мертвой зоны](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified)

Tomatoknight 27.09.17 в 14:42

0
Минутку...