szczecinski.eu

szczecinski.eu

  • Kurs React
  • Zaawansowany React
  • Kurs Redux
  • Kurs ES6
  • Blog
  • Kontakt

›Szybki kurs ES6

Szybki kurs ES6

  • Specyfikatory zasięgu - const, let
  • Template strings, tagged template strings
  • Arrow functions
  • Parametry domyślne, destructuring i rest
  • Skrócona notacja obiektowa, dynamiczne właściwości obiektu, spread
  • Klasy
  • Moduły
  • Kod asynchroniczny - Promise
  • Dekoratory

Moduły

Jednym z problemów występującym w JavaScript od samego początku był problem braku przestrzeni nazw - każda utworzona przez nas zmienna czy funkcja, o ile nie osadzona w wewnątrz przestrzeni innej funkcji znajdowała się w przestrzeni globalnej i była dostępna jako window.nazwaZmiennej - w przypadku kiedy korzystaliśmy z wielu bibliotek mogły pojawić się problemy z nadpisywaniem się wzajemnie funkcji czy zmiennych o tych samych nazwach.

Innym z problemów było samo udostępnianie i wykorzystywanie kodu - w tym celu po prostu dodawaliśmy plik z interesującym nas fragmentem JS do dokumentu HTML i w momencie załadowania kod był dostępny dla całej strony. Problemy oczywiście pojawiały się w momencie zwiększenia ilości kodu - długie ładowanie, skomplikowane zależności, problemy z utrzymaniem kodu rozproszonego w chaotyczny sposób po wielu plikach.

Problem ten próbowano rozwiązać na wiele sposobów, najpopularniejsze z nich to CommonJS i ES6 modules.

CommonJS

System modułów składa się z 2 części: pliku eksportującego dane.

Plik, który eksportuje dane w formacie CommonJS używa notacji module.exports i określa dwa typy eksportów:

  • eksport domyślny - oznaczony jako module.exports.default - każdy moduł może mieć maksymalnie jeden eksport domyślny
  • eksport nazwany - oznaczony jako modules.exports.NAZWA_EKSPORTU - każdy moduł może deklarować dowolną ilość nazwanych eskportów

Wszelkie wyeksportowane dane mogą zostać zaimportowane przez dowolny inny moduł/aplikację, zaś dane, które nie są eksportowane są stosowane jako prywatne API modułu i jeżeli nie udostępnimy interfejsu do ich modyfikacji nie będą one mogły być w żaden sposób modyfikowane.

// Math.js

const PI = 3.14;
const obwodKola = (r) => 2 * PI * r;

module.exports.pi = PI;
module.exports.detauls = obwodKola; 

// alternatywnie
module.exports = {
  PI,
  default: obwodKola
}

W celu uzyskania dostępu do wyeksportowanych danych z innego modułu używamy funkcji require. W przypadku modułów CommonJS odwołania do konkretnych eksportów jest dosyć oczywiste - wszystkie one stanowią pola na zaimportowanym obiekcie.

Domyślnie, jeżeli ścieżka do importowanego pliku nie zaczyna się od . oznacza to, że moduł powinien zostać odszukany w folderze node_modules. Zachowanie to może zostać zmodyfikowane w konfiguracji webpacka.

const MyMath = require('./Math.js');
console.log(MyMath.PI); // 3.14;

console.log(MyMath.default(2)); // 2 * PI * r = 12.56

// możemy także zaimportować określone elementy:
const PI = require('./Math.js').PI;
const obwodKola = require('./Math.js').default;

// zaimportuj moduł NPM left-pad z katalogu node_modules
const leftPad = require('left-pad');

Uwaga

Node (a także webpack) w celu optymalizacji wydajności traktuje każdy moduł jako singleton. Oznacza to, że przy kolejnych importach modułu o dokładnie tej samej ścieżce jego kod nie zostanie ponownie wywołany. Dodatkowo wszelkie wewnętrzne modyfikacje poprzez upublicznione API są dostępne również w zaimportowanych kopiach.

ES6 modules

ES6 definiuje własny format modułów, zachowujący ideę CommonJS ale wprowadzający nową składnię. ES6 modules oferują także dodatkowe zalety w postaci tree shaking (nie importowanie kodu, który nie jest wykorzystywany w aplikacji).

Odpowiednik kodu z poprzednich listingów stosujący zapis export:

// Math.js

export const PI = 3.14;
export default obwodKola = (r) => 2 * PI * r; // zwróć uwagę na brak const

// alternatywnie
exports = {
  PI
};

const obwodKola = (r) => 2 * PI * r; // zwróć uwagę na brak "const"
export default obwodKola;    

Odpowiednio, zamiast require używamy konstruktu import. Należy zwrócić uwagę, że eksport domyślny możemy zaimportować do naszej aplikacji nadając mu dowolną nazwę - nie musi w żaden sposób pokrywać się z nazwą eksportowanego obiektu znajdującą się w Math.js.

Uwaga

Pomimo że importowanie nazwanych eksportów wygląda podobnie do destrukturyzowania nie jest nim - nie można w ten sposób wydobyć pól składowych eksportu domyślnego.

import { PI } from "./Math.js";
console.log(PI); // 3.14;

import obwod from "./Math.js";
console.log(obwod(2)); // 2 * PI * r = 12.56

// możemy także zaimportować wiele rzeczy razem
import obwod, { PI } from "./Math.js";

// lub zaimportować wszystkie nazwane eskporty:
import * as MyMath from "./Math.js";
console.log(MyMath.PI);

// możemy także zmieniać nazwy eksportów nazwanych w momencie importu:
import { PI as prawiePi } from "./Math.js";
console.log(prawiePi); // 3.14
← KlasyKod asynchroniczny - Promise →
  • CommonJS
  • ES6 modules
Bartosz Szczeciński © 2019 Materiał dostępny na zasadach licencji MIT.