# Область видимости в JS

В JS есть глоальная и локальные области видимости

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

```javascript
if (true) {
  // локальная переменная
  let b = 17;
  console.log(b); // 17
}
console.log(b); // Uncaught ReferenceError: b is not defined
```

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

```javascript
let b = 0;
if (true) {
    b = 17;
    console.log(b); // 17
}
console.log(b); // 17
```

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

```javascript
// глобальная область видимости
let a = 5;
let b = 8;
let c = 20;
function fnA() {
  a = 7;
  b = 10;
  let b = 11;
  b = 13;
  function fnB() {
    let c = 25;
    console.log(a); // 7
    console.log(b); // 13
    console.log(c); // 25
  }
  fnB();
}

fnA();
```

<figure><img src="https://1562788351-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMyA51SCneIPcN69HMpat%2Fuploads%2FGEuNEm6NmvyLzKa6CSkl%2Fscope-chain.png?alt=media&#x26;token=09ab96ee-3c21-4395-ab10-9e9ed9cbe5b0" alt=""><figcaption></figcaption></figure>

### Значение переменной на момент вызова

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

```javascript
let name = 'Gizmo';

function sayName(){
    console.log(name);
}

name = 'Overfinch';
sayName(); //Overfinch
```

### Родительская область а не стэк вызова

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

```javascript
let userName = "Peter";

function sayUserName() {
    console.log(userName);
}

function sayUserNameAgain() {
    let userName = "Sarah";
    sayUserName();
}

sayUserNameAgain(); // Peter
```

### Устаревшее ключевое слово `var`

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

```javascript
if (true) {
    var b = 17;
}
console.log(b);
```

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

```javascript
// Global variable
const userName = "Peter";

// Outer function
function calcAge(birthyear) {
  const currentYear = 2021;
  const age = currentYear - birthyear;

   // inner block
  if (age <= 60) {
    var working = true;
    const message = \`Peter is still employed!\`;
    console.log(message);
  }

  // inner function
  function yearsToRetire() {
    const retirement = 60 - age;
    console.log(\`${userName} will be retired in ${retirement} years!\`);
  }

  yearsToRetire();
}

calcAge(1975);
```

<figure><img src="https://1562788351-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMyA51SCneIPcN69HMpat%2Fuploads%2FCyrJ0IaQoMKvkMGumHG4%2F2-scope-chain.png?alt=media&#x26;token=f1052058-d7e8-49c9-9e64-94cd8d61c83e" alt=""><figcaption></figcaption></figure>

Здесь `var working` транслируется в родительскую "зелёную" область видимости, а из неё доступен так же для функции `yearsToRetire()`
