Zmienne

Var

Przed ES6 sposobem deklaracji zmiennej było używanie słowa kluczowego var.

var foo = 'bar'

Nie tylko referencja zmiennej var może ulec zmianie, ale nawet sama zmienna moż być ponownie zadeklarowana.

var foo = 'bar'
foo = "rab"
foo // => "rab"
var foo = 42
foo // => 42

Funkcyjny zakres Var

Zmienne deklarowane przy użyciu słowa kluczowego var mają zakres funckji, a więc - chyba, że są zadeklarowane w zakresie globalnym - są wyłącznie dostępne w zakresie funkcji, w ramach, której zostały zadeklarowane.

var foo = 'bar'

function logFoo() {
  var foo = 'rab'
  console.log(foo)
}

console.log(logFoo()) // "rab" 
console.log(foo) // "bar"

if (true) {
  var foo = '42'
}

console.log(foo) // 42

Podciąganie (ang. hoisting) Var

Zmienne var - niezależnie od tego w jakim zakresie zostały zadeklarowane - są podciągane (ang. hoisted) przed wykonaniem codu, tzn. przenoszone na początek zakresu i inicjalizowane z wartością undefined.

function logVar() {
  console.log(foo)
  var foo = 'bar'
  console.log(foo)
}

logVar() // undefined "bar"

Let

W dodatku do var ES6 wprowadził słowa kluczowe let oraz const. let umożliwia definiowanie zmiennych, a const stałych.

Wartość referowana przez obie - zmienną var oraz zmienną let - może ulec zmianie, ale zmienna let - w przeciwieństwie do zmiennej var - nie może być ponownie zadeklarowana.

let foo = 'bar'
foo = 'rab'
foo // => "rab"
let foo = 42 // Uncaught SyntaxError: Identifier 'foo' has already been declared

Blokowe (aka leksykalne, aka statyczne) zakresowanie let

Zmienna zadeklarowana z let nie ma zakresu funkcyjnego, tak jak zmienna zadeklarowana z var, a zakres blokowy. Oznacza to, że dla zmiennych zadeklarowanych z let istnieje nie tylko oddzielny zakres globalny, oddzielny zakres funkcyjny, ale również oddzielny zakres w ramach danego bloku.

let foo = 'bar'

if (true) {
  let foo = 'rab'
}

console.log(foo) // "bar"

Const

ES6 wprowadziło możliwość deklarowania stałych używając słowa kluczowego const.

Nie tylko stałe nie mogą zostać ponownie zadeklarowane, ale również ich referencje nie mogą się zmienić. Pomimo tego, że referencja raz zadeklarowanej stałej nie może się zmienić, to nie oznacza to, że referowana wartość nie może ulec zmianie.

const foo = 'bar'
foo = 'rab' // Uncaught TypeError: Assignment to constant variable.

const foobar = { a: 1 }
foobar.a = 2
foobar // { a: 2 }

Stałe - tak jak zmienne deklarowane przy użyciu let - mają zakres leksykalny.