Czym jest zasięg (scope) w JavaScript? Zasięg globalny, modułowy, funkcyjny i blokowy.

Link do artykułu: Czym jest scope w JavaScript?

Zasięg (scope) to kolejne z podstawowych pojęć w JavaScripcie. Znajomość tego zagadnienia jest bardzo istotna dla każdego Front End Developera.

Czym jest zasięg (scope) w JavaScript?

Zasięg jest to obecny kontekst wykonywania, w którym są widoczne wartości, czyli zmienne, funkcje. Inaczej mówiąc, zasięg określa dostęp do zmiennych czy funkcji. Wartości poza zasięgiem nie są dostępne do użycia. Zasięg posiada kilka typów, które wymienię poniżej w artykule.

Dostęp do innych zasięgów jest zależny od hierarchii. Zasada jest taka, że z poziomu aktualnego kontekstu mamy dostęp do kontekstu nadrzędnego, natomiast nie mamy dostępu do kontekstu wewnątrz. Oznacza to, że jeśli utworzymy funkcję o nazwie A, a następnie wewnątrz utworzymy funkcję o nazwie B, to z poziomu funkcji B mamy dostęp do wszystkich wartości funkcji A. W drugą stronę już to nie zadziała. Później w artykule pojawią się przykłady, które rozwieją wszelkie wątpliwości.

Typy zasięgów

W JavaScript możemy wyróżnić kilka typów zasięgu:

  • Globalny (global scope) – domyślny zasięg dla kodu (script mode)
  • Modułowy (module scope) – zasięg dla kodu modułowego (module mode)
  • Funkcyjny (function scope) – zasięg stworzony przez funkcje
  • Blokowy (block scope) – zasięg dla zmiennych oraz stałych – let i const

Poniżej graficzne prezentacja zasięgów w JavaScript wraz z przykładami. Należy zauważyć, że jest to tylko przykład i to nie jest jedyna możliwa kombinacja.

Wizualne przedstawienie zasięgów w JavaScript wraz z przykładami - global, module, function, block scope
Wizualne przedstawienie zasięgów (scope) w JavaScript wraz z przykładami przygotowane przez devpebe.com

Czym jest zasięg globalny (global scope)

Globalny zasięg to domyślny zasięg dla całego kodu. Jest on najwyżej w hierarchii. Oznacza to, że każdy inny kontekst ma dostęp do zmiennych czy innych wartości zdefiniowanych w globalnym kontekście.

// GLOBAL SCOPE
const test = 'example'; // Global scope variable

function testFunction () {
  // FUNCTION SCOPE
  console.log(test); // This function has access to global scope variable
}

Czym jest zasięg modułowy (module scope)

To kolejny typ zasięgu, który oznacza, że kod w tym zakresie jest umieszczony w module. Kod poza tym modułem nie ma do niego dostępu. Jedyną możliwością, aby można było użyć funkcji czy zmiennej z modułu jest jej wyeksportowanie za pomocą słowa export. Najprościej mówiąc, kod umieszczony jest w osobnym pliku JavaScript i dodany do kodu HTML z atrybutem type='module'. Plik modułu tworzy swój własny kontekst, co wydaje się naturalnym zjawiskiem. Nie chcielibyśmy, aby kod z innego miejsca miał dostęp do kodu modułu, ponieważ powodowałoby niemałe problemy. Poniżej przykład.

Kod pliku module.js

// module.js content
// MODULE SCOPE
const moduleVariable = 'moduleValue';

Kod pliku index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Module scope example</title>
    </head>
    <body>
        <script>
          // GLOBAL SCOPE
          const test = 'example'; // Global scope variable
          
          function testFunction () {
            // FUNCTION SCOPE
            console.log(test); // This function has access to global scope variable
          }
        </script>
        <script src="module.js" type="module"></script>
    </body>
</html>

Powyższy przykład przedstawia osobny plik module.js, który jest dodany do HTML-u przy pomocy tagu script wraz z dodatkowym atrybutem type='module'. Kod JavaScript zdefiniowany bezpośrednio w pliku HTML (mógłby być zdefiniowany również w innym module) nie ma dostępu do kodu z pliku module.js.

Czym jest zasięg funkcyjny (function scope)?

W tym zasięgu podczas tworzenia funkcji tworzymy również zasięg funkcyjny. Będąc wewnątrz tej funkcji, mamy dostęp do nadrzędnych kontekstów. Co oznacza, że w przypadku gdy funkcja została stworzona wewnątrz innej funkcji, to ta wewnątrz (child function) ma dostęp do wartości z funkcji nadrzędnej (parent function) oraz pozostałych nadrzędnych zasięgów (w tym również zasięgu globalnym).

Przykłady poniżej.

function testFunction () {
  // FUNCTION SCOPE (testFunction)
  const testVariable = 'test'

  function example () {
    // FUNCTION SCOPE (example)
    const exampleVariable = 'example';
    console.log(testVariable) // prints 'test'
  }

  console.log(testVariable); // ReferenceError: testVariable is not defined
}

console.log(testVariable) // ReferenceError: testVariable is not defined
console.log(exampleVariable) // ReferenceError: testVariable is not defined

W powyższym przykładzie widać, że z testFunction nie mamy dostępu do zawartości example. Funkcja wewnątrz o nazwie example ma dostęp do zawartości nadrzędnych kontekstów.

Czym jest zasięg blokowy (block scope)?

Zasięg blokowy dotyczy zmiennych zdefiniowanych za pomocą słów let oraz const. W przypadku stworzenia takiej zmiennej wewnątrz bloku instrukcji warunkowej (if statement) dostęp do tej zmiennej poza tym blokiem nie będzie możliwy. To samo dotyczy innych instrukcji warunkowych takich jak for, while. Zmienne tworzone za pomocą słowa kluczowego var nie tworzą zasięgu blokowego.

function example () {
  const exampleVariable = 'example';

  if (exampleVariable) {
    const blockVariable = 'blockVariable';

    console.log(blockVariable); // prints 'blockVariable'
  }

  // FUNCTION example scope
  console.log(blockVariable) // ReferenceError: blockVariable is not defined
}

Czy znajomość tych zagadnień JavaScript jest potrzebna?

Jestem zdania, że znajomość tego zagadnienia jest potrzebna do zrozumienia działania JavaScript. Oczywiście, nie oznacza to, że bez tego nie będziemy w stanie programować w JS. Ten temat jest na tyle prosty i naturalny, że podczas praktyki szybko zrozumiemy zasadę działania. Dla bardziej doświadczonych front end developerów jest to o tyle istotne, że w przypadku uczenia osoby młodszej stażem musimy znać to zagadnienie, aby wiedzieć, jak to wytłumaczyć (tak samo, jak ja to robię, pisząc ten artykuł). Z całą pewnością znajomość tej koncepcji przyśpieszy naukę JavaScriptu.

Inne źródła tłumaczące scope wraz z przykładami

Pamiętam, jak czasami potrzebowałem innych przykładów czy innego wytłumaczenia, dlatego podaję inne źródła (przedstawionych również w innej formie). Jeśli będziecie szukać sami materiałów, zwróćcie uwagę na datę publikacji, ponieważ ES6 wprowadziło kilka zmian (m.in. zakres blokowy).

Scope na portalu MDN (EN)

Czym jest zakres zmiennych od „Jak zacząć programować?” na YouTube

Jak działa zakres w JavaScript

W moim artykule przedstawiłem czym jest zasięg (czy też inaczej zakres) zmiennych. Polecam również zapoznanie się z filmem od overmenta na YouTube, który przedstawia jak działa zakres (scope) w JavaScript. W tym filmie dowiesz się szczegółowego działa powstawania zakresów, co oznacza LHS (left hand side) oraz RHS (right hand side) oraz jak to wpływa na zarządzanie zmiennymi.

Polecam również ten film ze względu na dobrą jakość oraz przystępne przedstawienie tego tematu.

Jak działa zakres (scope) – overment na YouTube

Cały kod na Github

Wszystkie przykłady wraz z krótkim opisem dostępny jest również na moim GitHubie.

JavaScript scopes with examples (GitHub)

Podsumowanie

Zagadnienie zasięgu w JavaScript warto zrozumieć. Tłumaczy ono jak działa dostęp do wartości z różnych poziomów (funkcji, modułu). Początkującym osobom uczącym się JavaScript rozjaśni jego działanie. Teraz już znamy działanie zakresów w JavaScript.

Jak działa scope pojawia się często jako pytania rekrutacyjne! Z tego powodu warto również zrobić powtórzenie przed taką rozmową. 👋

Komentarze

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.