Lekce 3 - Třídy v TypeScriptu
V předešlém cvičení, Řešené úlohy k 1.-2. lekci v TypeScriptu, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
Dnes se podíváme na třídy, které sice již implementuje ES6, ale ty v TypeScriptu mají jednu velkou výhodu.
Většina věcí, která je obsažena v klasickém JavaScriptu, je použitelná i v TypeScriptu. To platí i pro cykly a podmínky. Vychází to z filozofie TypeScriptu, podle které nemá cenu implementovat věci, které standardní JavaScript obsahuje a dobře fungují.
Třídy (Classes)
Nyní se podíváme na třídy tak, jak je implementuje TypeScript. Pokud třídy znáte, tato část pro vás bude pravděpodobně jen opakování. Pokud je neznáte, doporučil bych vám minimálně článek o OOP v JavaScriptu První objektová aplikace v JS, ve kterém se dozvíte, co OOP je a k čemu jsou třídy.
Na začátku článku jsem zmínil, že třídy v TypeScriptu mají oproti implementaci z ES6 výhodu. Třídy v JavaScriptu totiž nefungují ve starších prohlížečích, v IE dokonce vůbec. Naštěstí TypeScript nám je přeloží a fungovat budou. Nyní si rychle prolétneme základní pojmy a uvedeme si několik příkladů. Budu používat souběžně anglické názvy, aby nás to nemátlo a abychom se něco naučili.
Konstruktor (Constructor)
Konstruktor je metoda, která se volá při vytvoření instance třídy. Slouží k nastavení vnitřního stavu objektu a k provedení případné inicializace.
This
Klíčové slovo this
obsahuje referenci na instanci objektu, ve
kterém se zrovna nacházíme. Používáme jej, když chceme přistoupit ke
členům dané instance. Jako členy nazýváme atributy nebo metody.
Modifikátory přístupu (Access modifiers)
Další důležitou součástí OOP v TypeScriptu jsou modifikátory přístupu. Ty určují, odkud a jakým způsobem je atribut nebo metoda třídy dostupná. TypeScript používá ve třídách 3 základní modifikátory:
public (výchozí)
Modifikátor public
je na rozdíl např. od jazyka C# výchozí. Pokud tedy nespecifikujeme jinak, všechny
členy třídy budou plně přístupné zvenku. Udělejme si malou ukázku:
class Zvire { public jmeno: string; public constructor(jmenujeSe: string) { this.jmeno = jmenujeSe; } public utikej(jakDaleko: number) { console.log(`${this.jmeno} utíkal ${jakDaleko}m.`); } }
Konstruktor při inicializaci nastaví atribut jmeno
. Toho
dosáhneme použitím slovíčka this
. Atribut jmeno
je použitý v metodě utikej()
. Tato metoda vytváří větu,
která nám řekne, jak naše zvíře utíkalo daleko.
Vytvoření instance a vypsání jména zvířete by vypadalo takto:
let gazela = new Zvire('Gonzales'); console.log(gazela.jmeno);
private
Pokud je člen označen jako private
, není možné k němu
přistoupit jinak než přímo zevnitř třídy. Upravme jméno našeho
zvířete tak, aby bylo jen soukromé:
class Zvire { private jmeno: string; public constructor(jmenujeSe: string) { this.jmeno = jmenujeSe; } public utikej(jakDaleko: number) { console.log(`${this.jmeno} utíkal ${jakDaleko}m.`); } }
Níže je vidět, že pokud se nyní pokusíme jméno zvířete vypsat mimo
třídu Zvire
, dostaneme chybu:
let gazela = new Zvire('Gonzales'); console.log(gazela.jmeno); // Tento řádek nyní způsobí chybu
V příkazovém řádku se objeví chybový text:
C:\Users\David\Desktop>tsc skript.ts skript.ts:14:20 - error TS2341: Property 'jmeno' is private and only accessible with in class 'Zvire'. 14 console.log(gazela.jmeno);
Označováním co největšího množství členů jako private se výrazně zminimalizuje možnost rozbít objekt zvenčí tím, že jej použijeme jinak, než zamýšlel jeho autor. I když mnohem větší význam má skrývat nějaké pomocné atributy tříd, např. logger, i jméno si nyní nemůžeme např. omylem vymazat:
gazela.jmeno = ""; // Tento řádek opět vyvolá chybu, jelikož jmeno je private
Na změnu jména bychom např. vystavili speciální metodu
zmenJmeno()
, kterou by bylo nutné explicitně zavolat.
protected
Modifikátor protected
se podobá private
. Na
rozdíl od něj však umožňuje i přístup k členům ze tříd, které z
dané třídy dědí, tedy z potomků. Dědičnost si ještě popíšeme o
kousek dále.
readonly
Atributy, které mají modifikátor readonly
, je možné
nastavit pouze při deklaraci nebo v konstruktoru. V ostatních případech
jsou, jak název napovídá, pouze pro čtení. Jedná se opět o mechanismus,
který nám pomáhá předejít nechtěným změnám, způsobenými např.
chybami v kódu.
Dědičnost (Inheritance)
Stejně jako ve většině objektově orientovaných jazyků i v TypeScriptu
ze sebe mohou třídy dědit. Dědění umožňuje rozšířit základní
třídu o nové atributy nebo metody a provádí se klíčovým slovem
extends
. Třída Opice
níže rozšiřuje naše
zvíře a tím obsahuje všechny jeho atributy a metody. Navíc přináší
svoji novou metodu, která je výhradně opičí, a to je
houpejSe()
. Protože chceme vědět, kolik mají opice běžně
ocasů, zavedli jsme atribut pocetOcasu
. Ten je pouze pro čtení,
protože nechceme, aby náš opičák o ocas přišel:
class Zvire { protected jmeno: string; public constructor(jmenujeSe: string) { this.jmeno = jmenujeSe; } public utikej(jakDaleko: number) { console.log(`${this.jmeno} utíkal ${jakDaleko}m.`); } } class Opice extends Zvire { readonly pocetOcasu = 1; houpejSe() { console.log(`Opicak ${this.jmeno} se houpe.`); } } let pepa = new Opice('Pepa'); pepa.utikej(150); // Pepa utíkal 150m. pepa.houpejSe(); // Opicak Pepa se houpe.
Všimněte si, že modifikátor přístupu k atributu jmeno
ve
třídě Zvire
jsme nastavili na protected
. To proto,
abychom k němu mohli přistupovat v potomkovi Opice
, v metodě
houpejSe()
.
Snad se vám všem podařilo pochopit, jak třídy fungují. V přiloženém
archivu najdete kód z tohoto článku. Kompilaci ze souboru .ts
nechám na vás
V následujícím cvičení, Řešené úlohy k 3. lekci v TypeScriptu, si procvičíme nabyté zkušenosti z předchozích lekcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 110x (1.31 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript