«Понятия не имею, почему это не работает».

Будучи младшим разработчиком, я сотни раз повторял эту фразу. Распространенная причина, по которой эта фраза произносится в подвалах, школах и кофейнях, — это простая проблема охвата.

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

Хорошее эмпирическое правило заключается в том, что вы можете смотреть только вверх в «цепочке прицелов», а не ниже себя.

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

Вот пример:

let birdHouse = 5

function buildHouse() {
console.log('A', birdHouse)
let doghouse = 10;
};
myHouse()
console.log('B', dogHouse)
// Console log 'A' will be 5 because it is called inside the function buildHouse and the interpreter can see the scope outside the function.
// Console log 'B' will be undefined because it is called in the global scope and the interpreter cannot peek inside the function buildHouse, where dogHouse is declared.

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

function buildHouse() {
if (1 === 1) {
let dogHouse = 10;
let birdHouse = 5;
};

console.log('A', birdHouse)
console.log('B', dogHouse)
buildHouse()
// When we run buildHouse() the console logs will both be undefined because "let" scopes them to the "if" block. Not a lot we can do with undefined variables.

Что произойдет, если мы используем «var» вместо «let»?

function buildHouse() {
if (1 === 1) {
var dogHouse = 10;
var birdHouse = 5;
};
console.log('A', birdHouse)
console.log('B', dogHouse)
buildHouse()
// When we run buildHouse() the console logs will be 5 and 10, respectfully. The interpreter will save the "var" declarations during the initial creation phase, making the labels available during code execution. This is called "hoisting".

Вот еще один краткий обзор глобальной, функциональной и блочной области видимости:

let test = 'red';
console.log('A', test)
// This will log as 'red', because it is declared in the global     scope.
function testFunction() {
  test = 'blue';
  console.log('B', test)
// This will log as 'blue', because it is declared in the functional scope.
  if( 1 === 1){
    let test = 'yellow';
    console.log('C', test)
// This will log as 'yellow', because it is declared in the block scope.
    }
  console.log('D', test)
// This will log as 'blue', because it is outside of the 'if' block scope where 'yellow' was declared as test, but inside the functional scope where 'blue' was declared as test.
}
testFunction()
console.log('E', test)
// This will log as 'red'. because it is outside of the functional scope where 'blue' was declared as test, but inside the global scope where 'red' was declared as test.

Написание более чистого кода, использование соответствующих объявлений и отладка — все это опирается на область действия. Как всегда, продолжайте читать, продолжайте учиться. Удачного кодирования.