TOC

This article has been localized into Czech by the community.

Třídy:

Statická pole a metody

Doposud jsou všechny členy třídy (pole a metody), které jsme v tomto tutoriálu používali, takzvané instancní členy. To znamená, že i když jsou deklarovány na třídě, potřebujete instanci třídy (objekt) pro přístup k tomuto členu.

To dává dokonalý smysl - stačí se podívat na naši předchozí třídu Pes s polem Jméno, pro ukládání jména psa. Obvykle byste chtěli vytvořit více než jednu instanci psa, takže Jméno by muselo patřit instanci třídy, a ne samotné třídě.

Nicméně, někdy má smysl definovat členy třídy, které nejsou vázány na instanci třídy. Členy, které nejsou instančními členy, se nazývají statické členy.

Statické metody

Nejčastěji používané jsou pravděpodobně statické metody, často používané pro pomocné funkce, které nejsou specifické pro instanci třídy, ale jsou dostatečně související, aby existovaly na třídě. Příkladem toho jsou takzvané "tovární metody", používané pro vytváření instancí třídy, obvykle na základě nějaké logiky, která by měla smysl mít vlastní funkci.

Abych vám ukázal příklad statické metody v akci, přidám metodu do naší třídy Pes z předchozích článků, aby vytvořila nového psa s náhodným věkem. To nemusí být v reálném světě užitečné, ale doufám, že vám to dá představu o tom, jak a kdy tuto techniku používat. Nejprve zde je metoda, kterou budu přidávat do třídy:

static CreateDog(name)
{
	let dog = new Dog();
	dog.name = name;
	dog.age = Math.floor(Math.random() * 20) + 1;
	return dog;
}

Všimněte si, že název metody je předponován klíčovým slovem static, což zřejmě označuje tuto metodu jako statickou metodu. Uvnitř vytvoříme novou instanci psa, přiřadíme předané jméno a poté vytvoříme náhodné číslo pro pole věku.

Při volání statické metody, ať už zevnitř třídy nebo zvenčí, vždy nejprve uvedete plný název třídy, poté tečku a pak název metody. Vypadalo by to takto:

Dog.CreateDog("Pluto");

Nyní se podívejme na kompletní příklad, včetně statické metody:

class Dog
{
	name;
	age;
	
	constructor(name, age)
	{
		this.name = name;
		this.age = age;
	}
	
	static CreateDog(name)
	{
		let dog = new Dog();
		dog.name = name;
		dog.age = Math.floor(Math.random() * 20) + 1;
		return dog;
	}
	
	Describe()
	{
		return this.name + " is " + this.age + " years old";
	}
}

let dog = new Dog("Dog Doe", 7);
alert(dog.Describe());

let randomizedDog = Dog.CreateDog("Pluto");
alert(randomizedDog.Describe());

Jak můžete vidět z posledních řádků příkladu, stále můžeme vytvořit Psa jako obvykle, ale jako alternativu nyní máme metodu CreateDog(), abychom získali psa s náhodným věkem.

Statické pole

Máme také statická pole, která jsou užitečná pro sdílení stejného kousku dat, které nejsou specifické pro jedinou instanci, například kešovaná data a/nebo data, která mají být použita statickými metodami. Pojďme rozšířit výše uvedený příklad o několik statických polí, ale nejdříve se podívejme, jak je statické pole definováno:

class Dog
{
	name;
	age;
	
	static dogNames = ["Dog Doe", "John Dog", "Pluto"];
	static dogCounter = 0;
	...

Jak vidíte, statická pole jsou pouze předponována klíčovým slovem static, stejně jako statické metody, a mohou být deklarována společně s běžnými poli. Pamatujte, že když deklarujete statické pole, toto pole je nyní sdíleno mezi všemi instancemi třídy. Jak uvidíte z následujícího kompletního příkladu, to může být velmi užitečné.

V tomto případě jsem deklaroval dva statické proměnné: Jednu pro sledování počtu vytvořených psů a druhou jako seznam možných jmen pro psy. Tato druhá bude použita k přeměně metody CreateDog() na zcela bezparametrovou funkci, která náhodně vybere jméno ze seznamu jmen psů a poté přiřadí i náhodný věk. Pojďme se podívat, jak to funguje:

class Dog
{
	name;
	age;
	
	static dogNames = ["Dog Doe", "John Dog", "Pluto"];
	static dogCounter = 0;
	
	constructor(name, age)
	{
		this.name = name;
		this.age = age;
		Dog.dogCounter++;
	}
	
	static CreateDog()
	{
		let dog = new Dog();
		dog.name = Dog.dogNames[Math.floor(Math.random() * Dog.dogNames.length)];
		dog.age = Math.floor(Math.random() * 20) + 1;
		return dog;
	}
	
	Describe()
	{
		return this.name + " is " + this.age + " years old";
	}
}

let dog1 = Dog.CreateDog();
alert(dog1.Describe());

let dog2 = Dog.CreateDog();
alert(dog2.Describe());

let dog3 = Dog.CreateDog();
alert(dog3.Describe());

alert("Total dogs: " + Dog.dogCounter);

Jak vidíte, metoda CreateDog() je nyní zcela bez parametrů - nevyžaduje žádný vstup, ale jednoduše vrátí psa se jménem z našeho seznamu, stejně jako s náhodným věkem.

Také si všimnete, že používáme statické pole dogCounter v konstruktoru, kde ho zvýšíme o jedničku. To nám umožňuje vždy sledovat, kolik psů bylo vytvořeno. Toto pole používáme v posledním řádku příkladu a, jak vidíte, stejně jako u statické metody, přistupujeme k němu odkazem na název třídy, pak tečkou a poté názvem pole.

Statické inicializační bloky

Jako poslední téma tohoto článku bych vám chtěl ukázat koncept statických inicializačních bloků. Ty jsou v podstatě jako konstruktory, ale pro statická pole. Můžeme tedy například definovat statické pole A přiřadit k němu takto hodnotu:

class Dog
{
	static dogNames = ["Dog Doe", "John Dog", "Pluto"];
	...

Co kdybychom chtěli udělat něco složitějšího než jen přiřadit jednu nebo několik statických hodnot k poli? K tomu může být mnoho důvodů a díky statickému inicializačnímu bloku můžeme přidat jakýkoliv druh logiky k inicializaci našich statických polí, včetně bloků try..catch pro zpracování chyb, inicializaci více polí atd.

Statický inicializační blok se do třídy přidává jednoduše použitím klíčového slova static, následovaným blokem kódu, takto:

class Dog
{
	static 
	{
		// Static initialization block
	}
	...

Můžete mít tolik bloků, kolik chcete - jsou jednoduše zpracovávány od začátku do konce. Ve většině případů však pravděpodobně budete potřebovat jen jeden. Také si všimněte, že statický inicializační blok je volán před samotným konstruktorem, což vám umožňuje spolehnout se na vaše statické pole, jakmile začnete třídu používat.

Abych vám ukázal, jak statický inicializační blok funguje v praxi, přepsal jsem naši třídu Pes. Nyní používá seznam zcela náhodně generovaných jmen jako seznam možných jmen pro psy. Přiznávám, že tato třída začíná vypadat trochu směšně a příliš složitě, ale prosím o trpělivost - doufám, že dokáže, jak mocnými mohou tyto funkce být a jak je lze použít.

A jen aby bylo dále ilustrováno, jak flexibilní jazyk JavaScript je, přidal jsem funkci, uvnitř statického inicializačního bloku, která vygeneruje náhodný řetězec, který budeme používat jako jméno psa:

class Dog
{
	
	name;
	age;
	
	static dogNames;
	static dogCounter;
	
	static 
	{
		alert("Initializing static fields...");
		
		function GenerateDogName() 
		{
			let result = "";
			const chars = "abcdefghijklmnopqrstuvwxyz";
			const charsLength = chars.length;
			const dogNameLength = 8;
			let counter = 0;
			while (counter < dogNameLength) 
			{
			  result += chars.charAt(Math.floor(Math.random() * charsLength));
			  if(result.length == 1)
			  	result = result.toUpperCase();
			  counter += 1;
			}
			return result;			
		}
		
		this.dogNames = [];
		while(this.dogNames.length < 5)
			this.dogNames.push(GenerateDogName());
		this.dogCounter = 0;
	}
	
	constructor(name, age)
	{
		this.name = name;
		this.age = age;
		Dog.dogCounter++;
	}
	
	static CreateDog()
	{
		let dog = new Dog();
		dog.name = Dog.dogNames[Math.floor(Math.random() * Dog.dogNames.length)];
		dog.age = Math.floor(Math.random() * 20) + 1;
		return dog;
	}
	
	Describe()
	{
		return this.name + " is " + this.age + " years old";
	}
}

let dog1 = Dog.CreateDog();
alert(dog1.Describe());

let dog2 = Dog.CreateDog();
alert(dog2.Describe());

let dog3 = Dog.CreateDog();
alert(dog3.Describe());

alert("Possible dog names: " + Dog.dogNames);
alert("Total dogs: " + Dog.dogCounter);

S touto poslední úpravou naše třída Pes nyní generuje seznam zcela náhodných jmen psů a ukládá je jako statické pole. Když vytvoříte nový objekt Pes, použije náhodně vybrané jméno ze seznamu náhodně generovaných jmen, zatímco zároveň sleduje, kolik psů bylo vytvořeno.

Všechny nové věci se dějí ve statickém inicializačním bloku, kde jsme vytvořili funkci nazvanou GenerateDogName(). Jednoduše vytváří sadu 8 náhodných znaků, které použijeme jako jméno. V dolní části statického inicializačního bloku volám GenerateDogName() ve while smyčce, abych přidal 5 náhodných jmen do našeho pole dogNames.

Ano, v tomto bodě je to docela směšný příklad, ale ukazuje několik technik, které by se mohly v různých případech ukázat jako velmi užitečné.

Shrnutí

Třída může mít statické členy ve formě statických polí a statických metod. Na rozdíl od instančních členů se na statické členy odkazuje přímo na třídě místo na instanci třídy. Obvykle se používají pro sdílení stejných dat mezi instancemi třídy (statická pole) a pro pomocnou funkcionalitu související s třídou (statické metody).

Statická pole lze deklarovat stejně jako běžná pole, a hodnoty jim lze přiřadit také při jejich deklaraci, ale jako alternativu můžete použít statický inicializační blok pro přiřazení složitějších hodnot statickým polím.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!