Pokazywanie postów oznaczonych etykietą scope. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą scope. Pokaż wszystkie posty

czwartek, 20 lipca 2017

example how and what for to use anonymous functions

I wrote some short introduction to anonymous function here, some time ago. I wrote some simple example, but no example for real life situation. Today I decided to write down an example which could be very useful on technical interview.

This is a very simple code example. We have a loop and inside this loop we create an array of functions. Every of functions logs i on the console. Then in the end we are calling the first function from the array.

var i = 0;
var funcArray = [];
for (; i < 20; i += 2) {
  funcArray.push(function() {
    console.log('i inside function', i);
  };
});

funcArray[0]();

What we want to achieve here is, to have an array of functions, to use inside of function a value of i. We cannot use index of function in array, as i is incremented by 2. This implementation looks like the easiest solution for our need.

So what would display on console as a result of this line funcArray[0]();? We expect it to be 0, but unfortunately it is... 20... WHY??

The answer is very easy - the scope. The thing which makes JavaScript harder to learn. But is very logic. Scope exists on function level (ES5) or on block level (ES6+). In this case inside of loop the function which uses scope variable i is created. But the function is called outside the loop, where i has a value 20 (the first value, which didn't meet the requirement, so there was no more incrementation of i).

So it doesn't matter which index would be called, the i outside of loop is always equal the first value, which didn't pass the condiition. It means we have to change the way how we create the scope for our function. And here the anonymous function will come with help.

What should be done, then? We have to create immediately invoked anonymous function, which will create the scope and will return the function which will be assigned to array element. As a parameter to anonymous function i will be passed to make it available inside the scope.

funcArray.push(( // immediately invoked function
// anonymous function, which gets i from scope as index
  function (index) {
    return function() { // returns a our function
      console.log('index inside function', index);
    }
  }
)(i)); // i passed to immediately invoked function

wtorek, 23 października 2012

zasieg zmiennych (scope) w JavaScript

Czytam sobie ostatnio do poduszki obiektowy JS, tak w ramach powtorzenia. Poniewaz dziergam w tym jezyku kilka lat juz coraz mniej mnie dziwi. Aczkolwiek kwestia, z ktora sobie dosc dlugo nie moglam poradzic byl zasieg zmiennych.

Zalozmy ze mamy kod:
var a = 1;
function f() {
   console.log('1. ' + a);
   var a = 2;
   console.log('2. ' + a);
}

f();

Zasieg zmiennych w JS jest ograniczony nie do nawiasow klamrowych, a do funkcji (od ES6 tylko dla słowa kluczowego var). Jesli zmienna jest w globalnej przestrzeni nazw (bez slowka var) to jest osiagalna praktycznie z dowolnego miejsca. Slowko var ogranicza zasieg, np do danego pliku czy funkcji.

Co bedzie wynikiem dzialania takiego kodu? Otoz zmienne sa widoczne w srodowiskach zawartych, ale nie na zewnatrz. Wiec jesli na zewnatrz funkcji mamy zdefiniowana zmienna a, a wewnatrz funkcji tworzymy ja jeszcze raz (slowko var), to JavaScript bedzie widzialo ta zmienna wewnatrz funkcji, jako zmienna o zasiegu tylko na te funkcje. Zaskutkuje to tym, ze pierwszy console.log wypisze nam undefined. Dlaczego? Bo wewnatrz funkcji ta zmienna JESZCZE nie ma wartości (interpreter już wie, że będzie stworzona, ale jeszce w tej linii kodu nie ma wartości; stąd dobra praktyka tworzyć WSZYSTKIE zmienne na początku funkcji/bloku kodu, żeby uniknąć takich sytuacji), wiec by default ma przypisana wartosc undefined. Drugi console.log wypisze juz, zgodnie z oczekiwaniami wartosc 2.


Zmodyfikujmy troche nasz kod:
var a = 1;
function f() {
   console.log('1. ' + a);
   a = 2;
   console.log('2. ' + a);
}

f();

Mala roznica. Wenatrz funkcji usunelam slowo var przed definicja zmiennej lokalnej a. Co to zmienia z punktu widzenia naszego programu? Wszystko. Przede wszytkim JavaScript sprawdzi, czy w zasiegu dostepnym z wnetrza funkcji nie ma juz zmiennej a. Jesli jest (jak w naszym przypadku) to zmieni jej wartosc.

Nasz program wypisze dwa razy wartosc zmiennej a widoczna wewnatrz funkcji. Za pierwszym razem bedzie to 1, a za drugim 2 (wartosc zmieniona juz wewnatrz funkcji)


To teraz tylko sprawdzenie, jak to wyglada na zewnatrz funkcji:
var a = 1;
function f() {
   console.log('1. ' + a);
   a = 2;
   console.log('2. ' + a);
}

console.log('3. ' + a);

f();

console.log('4. ' + a);

Zgodnie z oczekiwaniami zmienna istnieje w kazdym przypadku i zmiana jej wartosci wewnatrz funkcji skutkuje zmiana rowniez poza funkcja, bo operujemy na zmiennej o zakresie szerszym niz zakres tej funkcji.