Видимость var, let, const. Всплытие переменных
var
Видна внутри функции, в которой была объявлена
function foo () { for (var i = 0; i < 3; i++) { console.log(i) // 0, 1, 2 } console.log(i) // 3 }
После выполнения в цикле переменная i все еще видна внутри функции, поэтому примет значение 3.
Обладает свойством всплытия/поднятия
function foo () { var bar = 1 console.log(bar) // 1 var bar = 2 console.log(bar) // 2 }
При выполнении кода объявление переменной bar всплывет в начало функции, то есть код будет эквивалентен следующему
function foo () { var bar bar = 1 console.log(bar) // 1 bar = 2 console.log(bar) // 2 }
Как видно, всплывает только объявление переменной, присвоение значения - остается на прежнем месте.
А значит и следующий код, который выглядит слегка абсурдно, выполнится без ошибок:
function foo () { if (true) bar = 2 return bar var bar = 1 }
Объявление переменной bar всплывет в начало функции, поэтому из-за return будет проигнорировано только последнее присваивание значения, но функция все равно вернет значение 2.
Записывается в свойство window/global при объявлении вне функции
var bar = 1 function foo () { var bar = 2 console.log(bar) // 2 console.log(window.bar) // 1 } console.log(bar) // 1
Внешняя переменная не будет перезаписана при объявлении внутренней переменной. К внешней переменной можно обратиться через window.
let
Видна только внутри блока { ... }
let foo = 1 if (true) { let foo = 2 console.log(foo) // 2 } console.log(foo) // 1
Так как переменные, объявленные с помощью let, видны только внутри логического блока, то в данном коде не будет никаких пересечений или переопределений.
Видна только после объявления и не может быть переопределена
function foo () { if (true) bar = 2 // ReferenceError: bar is not defined return bar let bar = 1 }
В данном случае получим ошибку, так как в отличие от var, объявление переменной bar через let не всплывает в начало функции.
function foo () { let bar = 1 console.log(bar) let bar = 2 // SyntaxError: Identifier 'bar' has already been declared console.log(bar) }
В таком случае тоже получим ошибку, так как в пределах блока { ... } уже была определена переменная bar.
const
Отличается от let только тем, что значение константы не может быть перезаписано.
let foo = 1 foo = 2 console.log(foo) // 2 const bar = 1 bar = 2 // TypeError: Assignment to constant variable console.log(bar)
Однако, если константой является объект, то его свойства по прежнему могут изменяться.
const obj = { foo: 1 } obj.foo = 2 console.log(obj) // { foo: 2 }