14. Továrny a třídy

Články

  • https://exploringjs.com/impatient-js/ch_proto-chains-classes.html 90% vysvětlení řetězení prototypů
  • https://www.javascriptjanuary.com/blog/es6-classes 100% nová ochrana klíčových slov
  • Jak používat třídy v JavaScriptu — Tania Rascia 100% mág &hrdina instance podtříd proto
  • Třídy JavaScriptu — Under The Hood — Třída Majid 100% =mix funkce konstruktoru a prototypů, problémy funkce konstruktoru a prototypy
  • Funkce Class vs. Factory:zkoumání cesty vpřed — Cristi Salcescu
  • Jak třídy ES6 skutečně fungují a jak si vytvořit své vlastní – Robert Grosse 50 %
  • Snadný průvodce k pochopení tříd v JavaScriptu 100% vývojář a člověk
  • https://javascript.plainenglish.io/factories-are-still-better-than-classes-in-javascript-47f15071904e továrna vs třída

V Javascriptu existují dva způsoby vytváření objektů; továrny a třídy.

Továrny

Tovární funkce je funkce, která vrací objekt.

const RocketShipFactory = (c) => {
  const color = c;

  return {
    fly: () => console.log(`The ${color} rocketship has launched.`),
    land: () => console.log(`The ${color} rocketship has landed.`)
  } 
}

const spaceX = RocketShipFactory('black');
spaceX.fly();

Nad úryvkem je jednoduchá tovární funkce pro vytvoření spaceX objekt.

Uzavření

Co mě zajímá, je to, že tovární vzor obvykle používá uzavření pro zapouzdření dat. Ve výše uvedeném úryvku color proměnná je nepřístupná v globálním rozsahu, ale můžeme k ní přistupovat nepřímo přes fly nebo land metoda.

console.log(spaceX.color); // undefined

Třídy jsou jen „syntaktický cukr“ prototypové dědičnosti. Účelem třídy je nastavit prototypový řetězec mezi class.prototype a instancemi. Nejprve se podívejme na prototyp.

Prototyp

V javascriptu jsou všechny objekty vzájemně propojeny prostřednictvím něčeho, co se nazývá „prototypový řetězec“.

Třída je pouze šablona prototypu

Jedna věc, která je velmi důležitá, je, že instance vytvořené třídou odkazují na class.prototye, nikoli na třídu samotnou.

class Person {
  constructor(name) {
    this.name = name;
  }
  describe() {
    return 'Person named '+this.name;
  }
}

const Jane = new Person('jane');
console.log(jane.describe());

Ve výše uvedeném úryvku objekt Jane je instancí třídy Person . Takže Jane je propojen s Person.prototype s prototypovým řetězcem, nikoli s třídou Person sám.

._proto _ vs .prototype

Výše uvedený graf má vlastnosti zvané __proto__ a prototype . Co to je?

__proto__ vlastnost je pseudovlastnost pro přístup k prototypu objektu. Takže Jane 's __proto__ vlastnost ukazuje na Person.prototype objekt.

prototype vlastnost ukazuje na prototyp všech instancí třídy. To znamená, že Person prototype třídy vlastnost ukazuje na Person.prototype .

Navíc objekt Person.prototype 's constructor vlastnost ukazuje na samotnou třídu.

Všechny metody (kromě statických) třídy jsou uloženy v prototypu.

Další pravdou, která je důležitá, je, že všechny metody kromě statických metod deklarovaných uvnitř třídy jsou uloženy v prototypu.

Zpět k předchozímu příkladu můžeme vidět, že describe metoda je ve skutečnosti uložena uvnitř Person.prototype objekt. To je důvod, proč tuto třídu nazýváme pouze šablonou/syntaktickým cukrem prototypového programování.
Ale statické metody jsou uloženy v samotné třídě.

Třídy

normální a statické metody

Normální metody se dědí z tříd na instance, ale statické metody se nedědí a měly by se používat se samotnou třídou.

funkce konstruktoru

Funkce konstruktor nám pomáhá inicializovat s počtem parametrů, které by byly přiřazeny jako vlastnosti this , což je třída sama o sobě.

Getters/Setters

Funkce Getter používá get klíčové slovo pro získání hodnoty vlastnosti a Setter použije set klíčové slovo pro nastavení hodnoty vlastnosti. Může být použit pro zapouzdření dat nebo pro použití metody jako je vlastnost.

class Person {
  constructor(name){
    this._name = name;
  }
  get name() {
    return this._name;
  }
}

const Jane = new Person('jane');
console.log(Jane.name); // 'jane'
Jane.name = "alex";
console.log(Jane.name); // 'jane'

Můžeme skrýt _name majetek a nebude upravován. Také můžeme zavolat name metoda jako vlastnost.

Podtřídy

Pomocí podtříd můžeme vytvořit třídu, která je podobná nebo rozšířená z původních tříd.

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

sayName() {
    console.log("My name is " + this.name);
  }
}

class Developer extends Person {
  constructor(name) {
    super(name);
    this.name = name;
  }

getBio() {
    super.sayName();
    console.log("I am a developer");
  }
}

let ReactGuy = new Developer("Lawrence Eagles");
ReactGuy.getBio(); // "My name is Lawrence Eagles"
               // "I am a developer"

rozšířit klíčové slovo

extend klíčové slovo vytváří podtřídy.

super klíčové slovo

super klíčové slovo se používá pro přístup a volání funkcí z rodiče objektu (původní třída). Ve výše uvedeném úryvku super.sayName() volá sayName metoda třídy Person . Jedna věc, kterou je třeba zkontrolovat, je this v sayName metoda odkazuje na ReactGuy instance, nikoli třída samotná.

Pokud super klíčové slovo je voláno uvnitř konstruktoru, volá funkci konstruktoru rodičovské třídy. Například super(name) se nazývá uvnitř Developer funkce konstruktoru. Takže proměnná parametru name budou předány funkci konstruktoru Person třída.

Vztah prototypu

Když je subcalss vytvořen z původní třídy, původní třída se stává prototypem subcalss. Například třída Person je Developer prototyp.

class Person {
  constructor(name) {
    this.name = name;
  }
  describe() {
    return `Person named ${this.name}`;
  }
  static logNames(persons) {
    for (const person of persons) {
      console.log(person.name);
    }
  }
}

class Employee extends Person {
  constructor(name, title) {
    super(name);
    this.title = title;
  }
  describe() {
    return super.describe() +
      ` (${this.title})`;
  }
}

const jane = new Employee('Jane', 'CTO');
assert.equal(
  jane.describe(),
  'Person named Jane (CTO)');

Ve výše uvedeném úryvku Employee je podtřídou Person a Jane je instancí podtřídy Employee . Prototypový řetěz vypadá podle následující tabulky.

Továrna vs. třídy

Oba mají různé výhody a nevýhody.

Zapouzdření dat

Za prvé, sektor je zapouzdření dat. V továrně můžeme pomocí uzavření ovládat, zda chceme, aby data byla soukromá nebo veřejná. Ve třídách to však není tak jednoduché.

Třídy; zapouzdření dat / getter &setter

Jak jsem již zmínil, getter &setter se používá pro zapouzdření dat ve třídách. Není však systémově zapouzdřen. Znamená to, že je to vlastně modifikovatelné.

class Person {
  constructor(name){
    this._name = name;
  }
  get name() {
    return this._name;
  }
}

const Jane = new Person('jane');
console.log(Jane.name);
Jane._name = "alex";
console.log(Jane.name);

Pokud změníme přiřazení vlastnosti _name , hodnota vrácená z name změny metody. Ačkoli v javascriptu konvenčně slibujeme, že nebudeme měnit proměnnou pomocí _ předpona. Ale je to možné.

Třídy; zapouzdření dat / předpona #

Předpona # byla nedávno zavedena pro pole soukromé třídy.

class CoffeeMachine {
  #waterLimit = 200;

  #checkWater(value) {
    if (value < 0) throw new Error(".");
    if (value > this.#waterLimit) throw new Error(".");
  }

}

let coffeeMachine = new CoffeeMachine();

coffeeMachine.#checkWater(); // Error
coffeeMachine.#waterLimit = 1000; // Error

Vypadá to hezky, ale jeden problém je v tom, že soukromé metody ve třídách také nejsou přístupné v podtřídách.

toto klíčové slovo

Ve třídě this klíčové slovo prochází v určitých situacích určitým zmatkem v rozsahu. Tyto situace jsou, když this se používá ve vnořené funkci nebo ve funkci zpětného volání.

Řešením tohoto problému je funkce šipky .

class Car {
  constructor(maxSpeed){
    this.maxSpeed = maxSpeed;
  }
  drive = () => {
    console.log(`driving ${this.maxSpeed} mph!`)
  }
}

Toto funguje za každých okolností.

Cena paměti

Náklady na paměť jsou problémem pro tovární funkci. Na rozdíl od třídy, která v prototypu ukládá metody pouze jednou, tovární funkce vytvářejí kopii každé metody na každé instanci, kterou vytvoří. To může být problematické, pokud se počet instancí zvýší.