Potřebuje JavaScript třídy?

Ať se vám to líbí nebo ne, ECMAScript 6 bude mít třídy1 . Koncept tříd v JavaScriptu byl vždy polarizující. Někteří lidé milují beztřídní povahu JavaScriptu konkrétně proto, že se liší od ostatních jazyků. Na druhé straně jsou lidé, kteří nenávidí beztřídní povahu JavaScriptu, protože je jiný než ostatní jazyky. Jednou z největších mentálních překážek, které lidé musí přeskočit, když přecházejí z C++ nebo Java na JavaScript, je nedostatek tříd a nechal jsem lidi vysvětlit, že to byl jeden z důvodů, proč se jim JavaScript buď nelíbil, nebo se rozhodli ne. pokračovat v učení.

JavaScript neměl formální definici tříd od svého prvního vytvoření a to způsobilo zmatek hned od začátku. Nechybí JavaScriptové knihy a články hovořící o třídách, jako by to byly skutečné věci v JavaScriptu. To, co označují jako třídy, jsou ve skutečnosti pouze vlastní konstruktory používané k definování vlastních typů odkazů. Referenční typy jsou nejblíže třídám v JavaScriptu. Obecný formát je většině vývojářů dobře známý, ale zde je příklad:

function MyCustomType(value) {
    this.property = value;
}

MyCustomType.prototype.method = function() {
    return this.property;
};

Na mnoha místech je tento kód popsán jako deklarující třídu s názvem MyCustomType . Ve skutečnosti vše, co dělá, je deklarovat funkci s názvem MyCustomType který je určen k použití s ​​new k vytvoření instance referenčního typu MyCustomType . Ale na této funkci není nic zvláštního, nic, co by říkalo, že se nějak liší od jakékoli jiné funkce, která se nepoužívá k vytvoření nového objektu. Je to použití funkce, které z něj dělá konstruktor.

Kód ani nevypadá, že by definoval třídu. Ve skutečnosti je velmi málo zřejmý vztah mezi definicí konstruktoru a jednou metodou na prototypu. Pro nové vývojáře JavaScriptu to vypadají jako dva zcela samostatné části kódu. Ano, mezi těmito dvěma částmi kódu je zřejmý vztah, ale nevypadá to jako definování třídy v jiném jazyce.

Ještě více matoucí je, když lidé začnou mluvit o dědictví. Okamžitě začnou používat termíny jako podtřídy a supertřídy, koncepty, které dávají smysl pouze tehdy, když máte třídy, se kterými můžete pracovat. Syntaxe dědičnosti je samozřejmě stejně matoucí a podrobná:

function Animal(name) {
    this.name = name;
}

Animal.prototype.sayName = function() {
    console.log(this.name);
};

function Dog(name) {
    Animal.call(this, name);
}

Dog.prototype = new Animal(null);
Dog.prototype.bark = function() {
    console.log("Woof!");
};

Dvoufázový proces dědičnosti pomocí konstruktoru a přepsání prototypu je neuvěřitelně matoucí.

V prvním vydání Professional JavaScript for Web Developers , použil jsem výhradně termín „třída“. Zpětná vazba, kterou jsem obdržel, naznačovala, že to lidé považují za matoucí, a tak jsem všechny odkazy na „třída“ ve druhém vydání změnil na „typ“. Od té doby tuto terminologii používám a pomáhá to odstranit spoustu zmatků.

Stále však existuje do očí bijící problém. Syntaxe pro definování vlastních typů je matoucí a podrobná. Dědičnost mezi dvěma typy je vícekrokový proces. Neexistuje žádný snadný způsob, jak zavolat metodu na supertyp. Sečteno a podtrženo:je těžké vytvářet a spravovat vlastní typy. Pokud si nemyslíte, že jde o problém, podívejte se na počet knihoven JavaScriptu, které zavedly svůj vlastní způsob definování vlastních typů, dědičnosti nebo obojího:

  • YUI – má Y.extend() provést dědictví. Také přidá superclass vlastnost při použití této metody.2
  • Prototyp – má Class.create() a Object.extend() pro práci s objekty a „třídami“.3
  • Dojo – má dojo.declare() a dojo.extend() .4
  • MooTools – má vlastní typ nazvaný Class pro definování a rozšiřování tříd.5

Je docela zřejmé, že existuje problém, když tolik knihoven JavaScriptu definuje řešení. Definování vlastních typů je chaotické a není vůbec intuitivní. Vývojáři JavaScriptu potřebují něco lepšího, než je současná syntaxe.

Třídy ECMAScript 6 ve skutečnosti nejsou nic jiného než syntaktický cukr nad rámec vzorů, které již znáte. Zvažte tento příklad:

class MyCustomType {
    constructor(value) {
        this.property = value;
    }

    method() {
        return this.property;
    }
}

Tato definice třídy ECMAScript 6 ve skutečnosti odsuzuje předchozí příklad v tomto příspěvku. Objekt vytvořený pomocí této definice třídy funguje přesně stejně jako objekt vytvořený pomocí definice konstruktoru z dřívější doby. Jediným rozdílem je kompaktnější syntaxe. Jak je to s dědictvím:

class Animal {
    constructor(name) {
        this.name = name;
    }

    sayName() {
        console.log(this.name);
    }
}

class Dog extends Animal {
    constructor(name) {
        super(name);
    }

    bark() {
        console.log("Woof!");
    }
}

Tento příklad odsuzuje předchozí příklad dědičnosti. Definice tříd jsou kompaktní a neohrabaný vícekrokový vzor dědičnosti byl nahrazen jednoduchým extends klíčové slovo. Získáte také výhodu super() uvnitř definic tříd, takže nemusíte odkazovat na supertyp na více než jednom místě.

Veškerý současný návrh třídy ECMAScript 6 je jednoduše nová syntaxe nad rámec vzorů, které již znáte v JavaScriptu. Dědičnost funguje stejně jako vždy (řetězení prototypu plus volání konstruktoru supertypu), do prototypů se přidávají metody a v konstruktoru se deklarují vlastnosti. Jediný skutečný rozdíl je méně psaní pro vás (žádná slovní hříčka). Definice tříd jsou pouze definice typů s jinou syntaxí.

Takže zatímco některým to vyhovuje, protože ECMAScript 6 zavádí třídy, mějte na paměti, že tento koncept tříd je abstraktní. To zásadně nemění to, jak JavaScript funguje; nepředstavuje novou věc. Třídy jsou prostě syntaktický cukr nad vlastními typy, se kterými už nějakou dobu pracujete. To řeší problém, který má JavaScript již dlouhou dobu, a to je upovídanost a zmatek při definování vlastních typů. Osobně bych rád použil klíčové slovo type místo class , ale na konci dne je to jen otázka sémantiky.

Potřebuje tedy JavaScript třídy? Ne, ale JavaScript rozhodně potřebuje čistší způsob definování vlastních typů. Náhodou má způsob, jak to udělat, v ECMAScript 6 název „class“. A pokud to vývojářům z jiných jazyků pomůže usnadnit přechod do JavaScriptu, pak je to dobrá věc.

Překlady

  • Ukrajinský překlad od týmu Jeweell

Odkazy

  1. Maximálně minimální třídy ↩

  2. YUI extend() ↩

  3. Prototypové třídy a dědičnost ↩

  4. Vytváření a vylepšování lekcí Dojo ↩

  5. Třída MooTools ↩