JavaScript - zasięg, hoisting, zmienne
Przydatne linki
Przechowywanie zmiennych
LocalStorage - pamięć podręczna/lokalna
LocalStorage przechowuje dane przez wszystkie sesje.
Zapis:
localStorage['myKey'] = 'somestring'; // only strings
Odczyt:
var myVar = localStorage['myKey'] || 'defaultValue';
Przechowywanie wartości złożonych można uzyskać poprzez zastosowanie JSON.
Zapis:
localStorage['myKey'] = JSON.stringify(myVar);
Odczyt:
var stored = localStorage['myKey'];
if (stored) myVar = JSON.parse(stored);
else myVar = {a:'test', b: [1, 2, 3]};
Domknięcia i zasięg zmiennych
Domknięcia oznaczają to, że zasięg zawsze posiada dostęp do zewnętrznego zasięgu, w którym został zdefiniowany.
Ponieważ zasięg w JavaScript można definiować tylko poprzez funkcję, wszystkie funkcje domyślnie zachowują się jak domknięcia.
Zasięg zmiennych w pętlach - przykład 1
W JavaScript pętle nie tworzą zasięgu. Dla poniższego kodu najlepiej obrazuje to drugi console.log
, gdzie zmienna x
przechowywana jest poza pętlą for
, ale nie znamy już jej wartości poza funkcją example
.
var x = "x spoza funkcji";
function example()
{
for (var i = 0; i < 1; i++)
{
var x = "x z pętli for";
console.log(x); // x z petli for
}
console.log(x); // x z petli for
}
example();
console.log(x); // x spoza funkcji
Zasięg zmiennych w pętlach - przykład 2
Poniższy przykład wypisze dziesięc razy liczbę 10 w konsoli (a nie od 0 do 9), ponieważ kod wewnątrz pętli jest opóźniony i wyświetla 10 razy ostatnią wartość i
.
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
Konieczne jest przekopiowanie wartości i
jak na poniższym przykładzie.
//wersja 1
for(var i = 0; i < 10; i++) {
(function(e) {
setTimeout(function() {
console.log(e);
}, 1000);
})(i);
}
//wersja 2
for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
}
Node.js - przykład 3
Pętla 2 implementuje funkcję opakowującą, która zapewnia domknięcie funkcji asynchronicznej logCar()
. Kod w linii 8-13 implementuje podstawowe wywołanie zwrotne, co przekłada się na wyświetlanie jedynie ostatniej wartości z pętli w każdej iteracji. Kod 15-22 jest już prawidłowy.
function logCar(logMsg, callback){
process.nextTick(function() {
callback(logMsg);
});
}
var cars = ["Ferrari", "Porsche", "Bugatti"];
// pętla 1
for (var idx in cars){
var message = "Widziano samochód " + cars[idx];
logCar(message, function(){
console.log("Normalne wywołanie zwrotne: " + message);
});
}
// pętla 2
for (var idx in cars){
var message = "Widziano samochód " + cars[idx];
(function(msg){
logCar(msg, function(){
console.log("Wywołanie zwrotne z domknięciem: " + msg);
});
})(message);
}
Na podstawie podrozdziału Implementowanie domknięcia w wywołaniach zwrotnych strona 89 z 4 rozdziału książki Node.js, MongoDB, AngularJS - Kompendium wiedzy. Brad Dayley
Hoisting i zasięg zmiennej
Dość istotny jest następujący przykład. Jeśli w danym zasięgu zakrywamy jakąś zmienną, a chcemy poznać jej wartość przed jej deklaracją w danym zasięgu, to hoisting sprawi, że wartość z poziomu wyżej zostanie przykryta wartością undefined
, dlatego też w poniższym przykładzie pierwszy console.log
zwraca taką wartość.
var x = 10;
function example2()
{
//var x - tutaj tak naprawdę się znajduje
console.log(x); // undefined
var x = 2;
console.log(x); // 2
}
example2();
console.log(x);
Kontekst this
function foo() {
console.log(this);
}
foo(); // logs out the global e.g. `window` in browsers
let bar = {
foo
}
bar.foo(); // Logs out `bar` as `foo` was called on `bar`
Źródło