Chodzi o to, że jak zagnieżdżasz kod w JS, to różne konstrukty języka (takie jak funkcje, bloki czy inne) mogą tworzyć własne środowisko leksykalne z własną widocznością zmiennych. I te nazwy mogą być przysłaniane. Np. gdybyś zmodyfikował powyższy przykład:
const outer = () => {
let car = "Skoda";
const inner = () => {
let car = 'Ferrari';
console.log(car);
}
inner();
}
outer();
to by wyświetliło Ferrari, bo stworzyłbyś nową zmienną o tej samej nazwie car
, która przysłoniłaby tę poprzednią. Tym niemniej tamta poprzednia zmienna dalej by istniała:
const outer = () => {
let car = "Skoda";
const inner = () => {
let car = 'Ferrari';
console.log("from inner", car)
}
inner();
console.log("from outer", car)
}
outer();
// from inner Ferrari
// from outer Skoda
oczywiście jakby zmienna nie zostałaby przesłoniona, to z funkcji inner
byłaby widoczna zmienna zadeklarowana w funkcji outer
, czyli let car = "Skoda";
z zakresu leksykalnego z funkcji outer
Tu trzeba wspomnieć, że używając starej opcji var
się deklarowało zmienne na poziomie funkcji (co jest wadą, bo wtedy zmienne mogą się łatwo kolidować na poziomie funkcji), natomiast zmienne deklarowane już za pomocą let
czy const
można zadeklarować na poziomie bloku:
let foo = 456;
if (true) {
let foo = 123;
console.log(foo); // 123
}
console.log(foo); // 456
for (let i = 0; i < 10; i++) {
}