Objektově orientovaný vzor:JavaScript třídy a PHP třídy

Napsal jsem článek o porozumění prototypům a dědičnosti v JavaScriptu pro DigitalOcean, ve kterém jsem vysvětlil, jak používat funkce konstruktoru a vytvářet nové objekty, které z nich dědí. Myslel jsem, že by bylo zajímavé přepsat úplně stejný kód jako třída JavaScript ES6 a třída PHP a získat stejný výstup. Zde je tedy srovnání stejného vzoru a výstupu v ES5, ES6 a PHP vedle sebe.

Pomocí tříd ES6 vysvětlím, co vzor dělá.

Vytvoříme třídu (návrh objektu) a rozšíříme třídu (dědičnost). Jako příklad používám třídy postav RPG.

// Creating a class
class Hero {}

// Extending a class
class Warrior extends Hero {}

Přidám constructor() funkce pro přiřazení dvou parametrů třídě.

class Hero {
  // Assigning parameters with constructor
  constructor(name, level) {
    this.name = name
    this.level = level
  }
}

// Extending a class
class Warrior extends Hero {}

Přidám také metodu.

class Hero {
  constructor(name, level) {
    this.name = name
    this.level = level
  }

  // Adding a method
  greet() {
    return `${this.name} says hello.`
  }
}

class Warrior extends Hero {}

Nyní upravíme zděděnou třídu a přidáme nový parametr. Používáme super() pro přístup k parametrům od rodiče – jinak by k nim zděděná třída nemohla přistupovat a pracovat s nimi.

class Hero { ... }

class Warrior extends Hero {
    // Adding a constructor
    constructor(name, level, weapon) {
        // Access and call function from parent
        super(name, level);

        this.weapon = weapon;
    }
}

Nakonec do rozšířené třídy přidáme metodu.

class Hero {}

class Warrior extends Hero {
  constructor(name, level, weapon) {
    super(name, level)

    this.weapon = weapon
  }

  // Adding a method
  attack() {
    return `${this.name} attacks with the ${this.weapon}.`
  }
}

Nyní, když jsou plány třídy a rozšířené třídy připraveny, můžeme vytvořit novou postavu, která má přístup k parametrům a metodám původní třídy a rozšířené třídy.

// Initialize individual character instance
const hero1 = new Warrior('Bjorn', 1, 'axe')

console.log(hero1.attack())
console.log(hero1.greet())

Úplný kód a výstup pro funkce a třídy konstruktoru JS a třídy PHP jsou uvedeny níže.

Třída JavaScript ES6

class klíčové slovo bylo zavedeno s ES6. Třídy jsou postaveny na prototypech v JavaScriptu.

class-es6.js
class Hero {
  constructor(name, level) {
    this.name = name
    this.level = level
  }

  greet() {
    return `${this.name} says hello.`
  }
}

class Warrior extends Hero {
  constructor(name, level, weapon) {
    // Access and call function from parent
    super(name, level)

    this.weapon = weapon
  }

  attack() {
    return `${this.name} attacks with the ${this.weapon}.`
  }
}

// Initialize individual character instance
const hero1 = new Warrior('Bjorn', 1, 'axe')

console.log(hero1.attack())
console.log(hero1.greet())
Výstup
Bjorn attacks with the axe.
Bjorn says hello.

Funkce konstruktoru JavaScript ES5

Funkce konstruktoru JavaScriptu byly vytvořeny jako pokus přenést funkčnost tradičního objektově orientovaného návrhu tříd do jazyka JavaScript.

constructor-functions-es5.js
function Hero(name, level) {
  this.name = name
  this.level = level
}

function Warrior(name, level, weapon) {
  // Access and call function from parent
  Hero.call(this, name, level)

  this.weapon = weapon
}

// Link prototypes and add prototype methods
Warrior.prototype = Object.create(Hero.prototype)

Hero.prototype.greet = function () {
  return this.name + ' says hello.'
}

Warrior.prototype.attack = function () {
  return this.name + ' attacks with the ' + this.weapon + '.'
}

// Initialize individual character instance
const hero1 = new Warrior('Bjorn', 1, 'axe')

console.log(hero1.attack())
console.log(hero1.greet())
Výstup
Bjorn attacks with the axe.
Bjorn says hello.

Třída PHP

Zde je jednoduchý příklad konstruktoru třídy PHP.

class-php.php

<?php

class Hero {
    public function __construct($name, $level) {
        $this->name = $name;
        $this->level = $level;
    }
    public function greet() {
        return "{$this->name} says hello.";
    }
}

class Warrior extends Hero {
    public function __construct($name, $level, $weapon) {
        // Access and call function from parent
        parent::__construct($name, $level, $weapon);

        $this->weapon = $weapon;
    }

    public function attack() {
        return "{$this->name} attacks with the {$this->weapon}.";
    }
}

// Initialize individual character instances
$hero1 = new Warrior('Bjorn', 1, 'axe');

echo $hero1->attack();
echo $hero1->greet();
Výstup
Bjorn attacks with the axe.
Bjorn says hello.

Samozřejmě, třídy JavaScriptu jsou „syntaktický cukr“ (fuj) nad prototypy, což znamená, že třídy ES6 ve skutečnosti neběží na objektově orientovaném modelu dědičnosti. Populární knihovny jako React však mají tendenci třídy hodně využívat, takže je dobré je znát. Příklad PHP ukazuje skutečnou třídu z tradičního objektově orientovaného systému, ale s tímto jednoduchým příkladem můžeme získat stejný výstup v obou směrech.

Osobně dávám přednost syntaktické soli.