/ Gists / JS Patterns

Gists - JS Patterns

On gists

Vue computed with private variable via IIFE

JS Patterns Vue.js

any-component.js #

const showThumbs = (() => {
  // really private ;-)
  const state = ref(props.enableThumbs)

  return computed({
    get: () => state.value,
    set: value => {
      state.value = value
    }
  })
  
})()

/*

-----------------------------------
Nejčastější použití je právě pro:
  - Vytvoření privátního scope
  - Enkapsulaci dat a logiky
  - Vyhnutí se globálnímu scope
  - Zachování stavu přes closure
 -----------------------------------
 * 1. Vytvoření privátního scope
 * - proměnné uvnitř neuniknou ven
 * - čisté API pro vnější svět
 */
const counter = (() => {
  let count = 0  // privátní proměnná
  return {
    increment() { count++ },
    getCount() { return count }
  }
})()

/**
 * 2. Vyhnutí se globálnímu scope
 * - dočasné proměnné zůstanou lokální
 * - neznečišťuje globální namespace
 */
(() => {
  const temp = 'nějaká dočasná proměnná'
  // temp existuje jen uvnitř, neznečišťuje globální scope
})()

/**
 * 3. Modulární pattern
 * - privátní metody a proměnné
 * - veřejné API
 */
const module = (() => {
  const privateVar = 'private'
  const privateMethod = () => { 
    console.log(privateVar) 
  }
  
  return {
    publicMethod() {
      privateMethod()  // má přístup k privátním věcem
    }
  }
})()

/**
 * 4. Closure pro zachování stavu
 * - privátní stav
 * - reaktivní hodnota
 */
const showThumbs = (() => {
  const state = ref(props.enableThumbs)  // privátní stav
  return computed({
    get: () => state.value,
    set: (value) => {
      state.value = value
    }
  })
})()

/**
 * 5. Vyhnutí se konfliktům
 * - lokální aliasy
 * - izolace kódu
 */
(() => {
  const $ = jQuery  // lokální alias pro jQuery
  // používání $ uvnitř neovlivní jiné knihovny používající $
})()

/**
 * 6. Inicializace
 * - nastavení při načtení
 * - konfigurace
 * - event listenery
 */
(() => {
  // nějaká inicializace
  const config = { 
    apiKey: 'xxx',
    endpoint: 'https://api.example.com'
  }
  
  // nastavení event listenerů
  document.addEventListener('DOMContentLoaded', () => {
    // inicializace UI
  })
  
  // další setup
  const init = () => {
    // ...
  }
  
  init()
})()


On gists

Vue.js design pattern

JS Patterns Vue.js

pattern.js #

// https://blog.logrocket.com/exploring-advanced-design-patterns-vue-js/
// + MORE ... builder, adapter more usable ...

// BUILDER

// FormBuilder.js
class FormBuilder {
  constructor() {
    this.formFields = [];
  }
  addTextField(name, label, placeholder = '') {
    this.formFields.push({
      type: 'text',
      name,
      label,
      placeholder,
    });
    return this; // Return the builder instance for method chaining
  }
  addNumberField(...) {
    // Add a number field
  }
  addSelectField(...) {
    // Add a select field
  }
  build() {
    return this.formFields;
  }
}
export default FormBuilder;


//  Form.vue 
import FormBuilder from './helpers/FormBuilder';

export default {
  data() {
    return {
      formFields: [],
      formData: {}, // Add a data property to store the form data
    };
  },
  created() {
    /* 
     * Use the FormBuilder class and its methods 
     * to construct the `formFields` object array 
     * with different form fields.
     */
    this.formFields = new FormBuilder()
      .addTextField('name', 'Name')
      .addNumberField(...)
      .addSelectField(...)
      .build();
  },
  methods: {
    handleSubmit() {
      // Log the form data when the form is submitted
      console.log(this.formData);
    },
  },
};



// ADAPTER
// UserAdapter.js
class UserAdapter {
  constructor(externalUserData) {
    this.externalUserData = externalUserData;
  }
  adapt() {
    /*
     * Adapt the external user data to match
     * the component's expected format.
     *
     * Considering the structure of the expected
     * response, grab the right object array
     * (`results`) and its only value.
     *
     * @link https://randomuser.me/api/
     */
    const userData = this.externalUserData.results[0];
    return {
      name: `${userData.name.first} ${userData.name.last}`,
      email: userData.email,
      gender: userData.gender,
      location: `${userData.location.city}, ${userData.location.country}`,
      displayPic: userData.picture.large,
    };
  }
}
export default UserAdapter;

import UserAdapter from './UserAdapter';

export default {
  data() {
    return {
      userAdapter: null,
      user: null
    };
  },
  created() {
    /*
     * Get user data from an external API 
     * with a different format.
     */
    async created() {
      try {
        // Make an API call
        const response = await fetch('...');
        if (!response.ok) {
          throw new Error('Failed to fetch external user data');
        }
        const externalUserData = await response.json();

        /*
         * Create an adapter to convert external weather data 
         * to the format expected by the component.
         */
        this.userAdapter = new UserAdapter(externalUserData);

        // Adapt the data to the component's expected format
        this.user = this.userAdapter.adapt();
      } catch (error) {
        console.error('Error fetching external user data:', error);
        this.errorMessage = 'Failed to load user data. Please try again later.';
      }
    },
  }
};




// Composable pattern
// userPreferences.js
import { ref } from 'vue';

const theme = ref('light');
const language = ref('english');
const notifications = ref(true);

// Getter for theme
const getTheme = () => theme.value;

// Setter for theme
const setTheme = (newTheme) => {
  theme.value = newTheme;
};

// Getter for language
const getLanguage = () => language.value;

// Setter for language
const setLanguage = (newLanguage) => {
  language.value = newLanguage;
};

// Getter for notifications
const getNotificationsEnabled = () => notifications.value;

// Setter for notifications
const setNotificationsEnabled = (enabled) => {
  notifications.value = enabled;
};

export {
  getTheme,
  setTheme,
  getLanguage,
  setLanguage,
  getNotificationsEnabled,
  setNotificationsEnabled,
};


// themeSelector.js
import { computed } from 'vue';
import { getTheme, setTheme } from '../utils/userPreferences';

export function useThemeSelection() {
  const selectedTheme = computed({
    get: () => getTheme(),
    set: (newTheme) => setTheme(newTheme),
  });
  return {
    selectedTheme,
  };
}

// ThemeSelector.vue
<template>
  <div>
    <label for="theme-switch">Theme</label>
    <select id="theme-switch" @change="handleChange" v-model="selectedTheme">
      <option value="light">Light</option>
      <option value="dark">Dark</option>
    </select>
  </div>
</template>
<script>
import { defineComponent } from 'vue';
import { useThemeSelection } from '../composables/themeSelector';

export default defineComponent({
  setup() {
    const { selectedTheme } = useThemeSelection();
    const handleChange = (event) => {
      const newTheme = event.target.value;
      selectedTheme.value = newTheme; // Set the new theme
    };
    return {
      selectedTheme,
      handleChange,
    };
  },
});
</script>


// AnyOther.vue
<template>
  <div class="settings">
    <div class="settings-row">
      <ThemeSelector />
      <div :class="selectedTheme">
        Here's how the {{ selectedTheme }} theme looks like.
      </div>
    </div>
  </div>
</template>

<script>
import { defineComponent } from 'vue';
import { useThemeSelection } from './composables/themeSelector';
import ThemeSelector from './components/ThemeSelector';

export default defineComponent({
  setup() {
    const { selectedTheme } = useThemeSelection();

    return {
      selectedTheme,
    };
  },
  components: {
    ThemeSelector
  },
});
</script>

<style>
.light {
  background-color: #fff;
  color: #000;
}
.dark {
  background-color: #000;
  color: #fff;
}
</style>

On gists

JS OOP Design Patterns

JavaScript-OOP JavaScript JS Patterns

patterns.js #

/*

https://blog.carlosrojas.dev/quick-reference-guide-to-design-patterns-in-js-1ebeb1e1c605

*/


/* Singleton */
class Animal {
  constructor() {
    if (typeof Animal.instance === 'object') {
      return Animal.instance;
    }

    Animal.instance = this;

    return this;
  }
}
export default Animal;


/* Prototype */
class Fruit {
  constructor(name, weight) {
    this.name = name;
    this.weight = weight;
  }

  clone() {
    return new Fruit(this.name, this.weight);
  }
}
export default Fruit;

const apple = new Fruit('Apple', 150);
const clonedApple = apple.clone();
console.log(apple);        // Originální ovoce
console.log(clonedApple);  // Klonované ovoce


/* Factory */
class MovieFactory {
  create(genre) {
    if (genre === 'Adventure') return new Movie(genre, 10000);
    if (genre === 'Action') return new Movie(genre, 11000);
  }
}

class Movie {
  constructor(type, price) {
    this.type = type;
    this.price = price;
  }
}
export default MovieFactory;


/* Abstract Factory */
function foodProducer(kind) {
  if (kind === 'protein') return proteinPattern;
  if (kind === 'fat') return fatPattern;
  return carbohydratesPattern;
}

function proteinPattern() {
  return new Protein();
}

function fatPattern() {
  return new Fat();
}

function carbohydratesPattern() {
  return new Carbohydrates();
}

class Protein {
  info() {
    return 'I am Protein.';
  }
}

class Fat {
  info() {
    return 'I am Fat.';
  }
}

class Carbohydrates {
  info() {
    return 'I am carbohydrates.';
  }
}
export default foodProducer;


/* Adapter */
class Soldier {
  constructor(level) {
    this.level = level;
  }

  attack() {
    return this.level * 1;
  }
}

class SuperSoldier {
  constructor(level) {
    this.level = level;
  }

  attackWithShield() {
    return this.level * 10;
  }
}

class SoldierAdapter {
  constructor(superSoldier) {
    this.superSoldier = superSoldier;
  }

  attack() {
    return this.superSoldier.attackWithShield();
  }
}
export { Soldier, SuperSoldier, SoldierAdapter };

// Vytvoření instance SuperSoldier
const superSoldier = new SuperSoldier(5);

// Vytvoření instance SoldierAdapter, který přijímá SuperSoldier jako argument
const soldierAdapter = new SoldierAdapter(superSoldier);

// Volání metody attack() na SoldierAdapteru, která skutečně volá attackWithShield() u SuperSoldiera
const result = soldierAdapter.attack();

console.log(result);  // Vypíše: 50 (5 * 10)



/* Bridge */


class Soldier {
  constructor(weapon) {
    this.weapon = weapon;
  }
}

class SuperSoldier extends Soldier {
  constructor(weapon) {
    super(weapon);
  }

  attack() {
    return 'SuperSoldier, Weapon: ' + this.weapon.get();
  }
}

class IronMan extends Soldier {
  constructor(weapon) {
    super(weapon);
  }

  attack() {
    return 'Ironman, Weapon: ' + this.ink.get();
  }
}

class Weapon {
  constructor(type) {
    this.type = type;
  }

  get() {
    return this.type;
  }
}

class Shield extends Weapon {
  constructor() {
    super('shield');
  }
}

class Rocket extends Weapon {
  constructor() {
    super('rocket');
  }
}
export { SuperSoldier, IronMan, Shield, Rocket };

// Vytvoření instancí zbraní
const shield = new Shield();
const rocket = new Rocket();

// Vytvoření instancí vojáků s různými zbraněmi
const superSoldier = new SuperSoldier(shield);
const ironMan = new IronMan(rocket);

// Útoky vojáků
console.log(superSoldier.attack());  // Vypíše: SuperSoldier, Weapon: shield
console.log(ironMan.attack());       // Vypíše: Ironman, Weapon: rocket


/* Composite */
//Equipment
class Equipment {
  getPrice() {
    return this.price || 0;
  }

  getName() {
    return this.name;
  }

  setName(name) {
    this.name = name;
  }
}

class Pattern extends Equipment {
  constructor() {
    super();
    this.equipments = [];
  }

  add(equipment) {
    this.equipments.push(equipment);
  }

  getPrice() {
    return this.equipments
      .map(equipment => {
        return equipment.getPrice();
      })
      .reduce((a, b) => {
        return a + b;
      });
  }
}

class Cabbinet extends Pattern {
  constructor() {
    super();
    this.setName('cabbinet');
  }
}

// --- leafs ---
class FloppyDisk extends Equipment {
  constructor() {
    super();
    this.setName('Floppy Disk');
    this.price = 70;
  }
}

class HardDrive extends Equipment {
  constructor() {
    super();
    this.setName('Hard Drive');
    this.price = 250;
  }
}

class Memory extends Equipment {
  constructor() {
    super();
    this.setName('Memory');
    this.price = 280;
  }
}

export { Cabbinet, FloppyDisk, HardDrive, Memory };

// Vytvoření jednotlivých listových tříd (FloppyDisk, HardDrive, Memory)
const floppyDisk = new FloppyDisk();
const hardDrive = new HardDrive();
const memory = new Memory();

// Vytvoření skříně a přidání jednotlivých listových tříd do skříně
const cabbinet = new Cabbinet();
cabbinet.add(floppyDisk);
cabbinet.add(hardDrive);
cabbinet.add(memory);

// Získání celkové ceny skříně
const totalPrice = cabbinet.getPrice();
console.log(`Total Price: ${totalPrice}`);  // Vypíše: Total Price: 600


/* Decorator */
class Notification {
  constructor(kind) {
    this.kind = kind || "Generic";
  }
  
  getInfo() {
    return `I'm a ${this.kind} Notification`;
  }
}

class FacebookNotification extends Notification {
  constructor() {
    super("Facebook");
  }
  
  setNotification(msg) {
    this.message = msg;
  }
  
  getInfo() {
    return `${super.getInfo()} with the message: ${this.message}`;
  }
}

class SMSNotification extends Notification {
  constructor() {
    super("SMS");
  }
  
  getInfo() {
    return super.getInfo();
  }
}
export { FacebookNotification, SMSNotification };

// Vytvoření instance SMSNotification
const smsNotification = new SMSNotification();
// Dekorace SMSNotification pomocí FacebookNotificationDecorator
const decoratedNotification = new FacebookNotificationDecorator(smsNotification);
// Získání informací o dekorované notifikaci
console.log(decoratedNotification.getInfo());
// Vypíše: I'm a SMS Notification decorated with Facebook feature


/* Facade */
class Cart {
  constructor() {
    this.discount = new Discount();
    this.shipping = new Shipping();
    this.fees = new Fees();
  }

  calc(price) {
    price = this.discount.calc(price);
    price = this.fees.calc(price);
    price += this.shipping.calc();

    return price;
  }
}

class Discount {
  calc(value) {
    return value * 0.85;
  }
}

class Shipping {
  calc() {
    return 500;
  }
}

class Fees {
  calc(value) {
    return value * 1.1;
  }
}

export default Cart;


/* FlyWeight */
class Ingredient {
  constructor(name) {
    this.name = name;
  }
  
  getInfo() {
    return `I'm a ${this.name}`
  }
}

class Ingredients {
  constructor() {
    this.ingredients = {};
  }

  create(name) {
    let ingredient = this.ingredients[name];
    if (ingredient) return ingredient;

    this.ingredients[name] = new Ingredient(name);

    return this.ingredients[name];
  }
}
export { Ingredients };


/* Proxy */
class Plane {
  fly() {
    return 'flying';
  }
}

class PilotProxy {
  constructor(pilot) {
    this.pilot = pilot;
  }

  fly() {
    return this.pilot.age < 18 ? `too young to fly` : new Plane().fly();
  }
}

class Pilot {
  constructor(age) {
    this.age = age;
  }
}

export { Plane, PilotProxy, Pilot };


/* Iterator */
class Iterator {
  constructor(el) {
    this.index = 0;
    this.elements = el;
  }

  next() {
    return this.elements[this.index++];
  }

  hasNext() {
    return this.index < this.elements.length;
  }
}

export default Iterator;

// Importujte váš Iterator
import Iterator from './Iterator';

// Vytvořte nějakou kolekci dat (v tomto případě pole).
const collection = ['Prvek 1', 'Prvek 2', 'Prvek 3'];

// Vytvořte instanci Iteratoru, předávejte kolekci jako argument konstruktoru.
const iterator = new Iterator(collection);

// Projděte kolekci pomocí Iteratoru.
while (iterator.hasNext()) {
  const element = iterator.next();
  console.log(element);
}



/* Mediator */

class TrafficTower {
  constructor() {
    this.airplanes = [];
  }

  getPositions() {
    return this.airplanes.map(airplane => {
      return airplane.position.showPosition();
    });
  }
}

class Airplane {
  constructor(position, trafficTower) {
    this.position = position;
    this.trafficTower = trafficTower;
    this.trafficTower.airplanes.push(this);
  }

  getPositions() {
    return this.trafficTower.getPositions();
  }
}

class Position {
  constructor(x,y) {
    this.x = x;
    this.y = y;
  }
  
  showPosition() {
    return `My Position is ${x} and ${y}`;
  }
}

export { TrafficTower, Airplane, Position };

const trafficTower = new TrafficTower();

const airplane1 = new Airplane(new Position(10, 20), trafficTower);
const airplane2 = new Airplane(new Position(30, 40), trafficTower);

// Informovat TrafficTower o pozici letadla.
airplane1.getPositions();

// Získat informace o pozicích ostatních letadel pomocí TrafficTower.
airplane2.getPositions();



/* State */
class OrderStatus {
  constructor(name, nextStatus) {
    this.name = name;
    this.nextStatus = nextStatus;
  }

  next() {
    return new this.nextStatus();
  }
}

class WaitingForPayment extends OrderStatus {
  constructor() {
    super('waitingForPayment', Shipping);
  }
}

class Shipping extends OrderStatus {
  constructor() {
    super('shipping', Delivered);
  }
}

class Delivered extends OrderStatus {
  constructor() {
    super('delivered', Delivered);
  }
}

class Order {
  constructor() {
    this.state = new WaitingForPayment();
  }

  nextPattern() {
    this.state = this.state.next();
  }
}

export default Order;


// Vytvořte instanci objednávky
const order = new Order();

// Zjistěte aktuální stav
console.log(order.state.name); // Výstup: 'waitingForPayment'

// Přejděte na další stav
order.nextPattern();

// Zjistěte nový stav
console.log(order.state.name); // Výstup: 'shipping'

// Přejděte na další stav
order.nextPattern();

// Zjistěte nový stav
console.log(order.state.name); // Výstup: 'delivered'



/* Strategy */
class ShoppingCart {
  constructor(discount) {
    this.discount = discount;
    this.amount = 0;
  }

  checkout() {
    return this.discount(this.amount);
  }

  setAmount(amount) {
    this.amount = amount;
  }
}

function guest(amount) {
  return amount;
}

function regular(amount) {
  return amount * 0.9;
}

function premium(amount) {
  return amount * 0.8;
}

export { ShoppingCart, guest, regular, premium };

// Importujte třídu ShoppingCart a slevové strategie
import { ShoppingCart, guest, regular, premium } from './ShoppingCart';

// Vytvořte instanci nákupního košíku s různými slevovými strategiemi
const cartGuest = new ShoppingCart(guest);
const cartRegular = new ShoppingCart(regular);
const cartPremium = new ShoppingCart(premium);

// Nastavte množství v košíku
cartGuest.setAmount(100);
cartRegular.setAmount(100);
cartPremium.setAmount(100);

// Proveďte platbu s různými slevovými strategiemi
console.log(cartGuest.checkout()); // Výstup: 100 (žádná sleva)
console.log(cartRegular.checkout()); // Výstup: 90 (10% sleva pro běžného zákazníka)
console.log(cartPremium.checkout()); // Výstup: 80 (20% sleva pro prémiového zákazníka)



/* Template */
class Tax {
  calc(value) {
    if (value >= 1000) value = this.overThousand(value);

    return this.complementaryFee(value);
  }

  complementaryFee(value) {
    return value + 10;
  }
}

class VAT extends Tax {
  constructor() {
    super();
  }

  overThousand(value) {
    return value * 1.1;
  }
}

class GST extends Tax {
  constructor() {
    super();
  }

  overThousand(value) {
    return value * 1.2;
  }
}

export { VAT, GST };


// Importujte třídy VAT a GST
import { VAT, GST } from './Tax';

// Vytvořte instanci třídy VAT a provedte výpočet daně
const vatTax = new VAT();
console.log(vatTax.calc(1200)); // Výstup: 1320 (včetně přirážky pro hodnoty nad 1000)

// Vytvořte instanci třídy GST a provedte výpočet daně
const gstTax = new GST();
console.log(gstTax.calc(1200)); // Výstup: 1440 (včetně přirážky pro hodnoty nad 1000)

On gists

Adapter

JS Patterns

adapter.js #

// Staré rozhraní
class OldCar {
  getSpeedInMPH() {
    return 60;
  }
}

// Nové rozhraní
class NewCar {
  getSpeedInKPH() {
    return 100;
  }
}


class CarAdapter {
  constructor(newCar) {
    this.newCar = newCar;
  }

  // Adapter převede metodu getSpeedInMPH() na metodu getSpeed() pro kompatibilitu
  getSpeed() {
    return this.convertMPHtoKPH(this.newCar.getSpeedInKPH());
  }

  convertMPHtoKPH(mph) {
    return mph * 1.60934;
  }
}


const newCar = new NewCar();
const adaptedCar = new CarAdapter(newCar);

console.log("Nové auto (v KPH):", newCar.getSpeedInKPH()); // Vypíše "Nové auto (v KPH): 100"
console.log("Staré auto (v MPH):", adaptedCar.getSpeed()); // Vy

On gists

Prototype

JS Patterns

prototype.js #

// We declare our prototype object with two methods
const enemy = {
    attack: () => console.log("Pim Pam Pum!"),
    flyAway: () => console.log("Flyyyy like an eagle!")
}

// We declare another object that will inherit from our prototype
const bug1 = {
    name: "Buggy McFly",
    phrase: "Your debugger doesn't work with me!"
}

// With setPrototypeOf we set the prototype of our object
Object.setPrototypeOf(bug1, enemy)

// With getPrototypeOf we read the prototype and confirm the previous has worked
console.log(Object.getPrototypeOf(bug1)) // { attack: [Function: attack], flyAway: [Function: flyAway] }

console.log(bug1.phrase) // Your debugger doesn't work with me!
console.log(bug1.attack()) // Pim Pam Pum!
console.log(bug1.flyAway()) // Flyyyy like an eagle!

On gists

Factory Method

JS Patterns

1.js #

// Abstraktní třída definující Factory Method
class AnimalFactory {
  createAnimal() {
    throw new Error("Metoda createAnimal musí být implementována.");
  }
}

// Konkrétní třída implementující Factory Method
class DogFactory extends AnimalFactory {
  createAnimal() {
    return new Dog();
  }
}

class CatFactory extends AnimalFactory {
  createAnimal() {
    return new Cat();
  }
}

// Abstraktní třída reprezentující objekty, které budeme vytvářet
class Animal {
  makeSound() {
    throw new Error("Metoda makeSound musí být implementována.");
  }
}

// Konkrétní třídy reprezentující objekty, které budeme vytvářet
class Dog extends Animal {
  makeSound() {
    console.log("Haf haf!");
  }
}

class Cat extends Animal {
  makeSound() {
    console.log("Mňau mňau!");
  }
}

// Použití Factory Method Pattern
function createAndMakeSound(animalFactory) {
  const animal = animalFactory.createAnimal();
  animal.makeSound();
}

// Použití Factory Method Pattern s různými Factory
const dogFactory = new DogFactory();
const catFactory = new CatFactory();

createAndMakeSound(dogFactory); // Vypíše "Haf haf!"
createAndMakeSound(catFactory); // Vypíše "Mňau mňau!"

On gists

Singleton

JS Patterns

Singleton1.js #

class Singleton {
  static instance = null;

  constructor() {
    if (Singleton.instance) {
      throw new Error("Singleton instance already exists. Use getInstance() method to access it.");
    }
    // Inicializace Singletonu zde
  }

  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }

  someMethod() {
    console.log("Metoda Singletonu");
  }
}

// Použití Singletonu
const singletonInstance1 = Singleton.getInstance();
const singletonInstance2 = Singleton.getInstance(); // Tady bude vyvolána chyba

console.log(singletonInstance1 === singletonInstance2); // Vrátí true, protože se jedná o stejnou instanci
singletonInstance1.someMethod(); // Vypíše "Metoda Singletonu"

On gists

Builder

JS Patterns

builder.js #

/* 
  URL: https://learn.coderslang.com/0076-javascript-design-patterns-builder/ 
*/

// how create object from literal
const Employee = {
  isAdmin: false,
  getRole: function() {
	  return this.isAdmin ? 'Admin' : 'RegularEmp';
  };
};

const emp1 = Object.create(Employee);
emp1.getRole(); //'RegularEmp'

const emp2 = Object.create(Employee);
emp2.isAdmin = true;
emp2.getRole(); //'Admin'


// BUILDER PATTERN (prenasi a pomaha tvorit objekty s mandatory parametry, nepovinne vytvori separatne)

class OTG {
	constructor(model, color, maxTemperature, maxTimeSelection) {
	  this.model = model;
	  this.title = 'OTG';
	  this.color = color;
	  this.maxTemperature = maxTemperature || 150;
	  this.maxTimeSelection = maxTimeSelection || 30;
	}
}

const redOTG = new OTG('LG', 'red');
const highTempOTG = new OTG('LG', 'black', 200);
const highendTimeOTG = new OTG('LG', 'red', '150', '60');


class OTGBuilder {
  constructor(model, color) {
    this.model = model;
    this.title = 'OTG';
    this.color = color;
  }
  setMaxTemperature(temp) {
    this.maxTemperature = temp;
    return this;
  }

  setMaxTimeSelection(maxTime) {
    this.maxTimeSelection = maxTime;
    return this;
  }

  build() {
    return new OTG(this.model, this.color,
    this.maxTemperature, this.maxTimeSelection);
  }
}

const basicOTG = new OTGBuilder('MorphyRichards', 'Black')
  .setMaxTemperature(250)
  .setMaxTimeSelection(60)
  .build();
  
  // or without mandatory params
  const default = new OTGBuilder('Generic OTG', 'White')
  .build();

On gists

Decorator

JS Patterns

decorator.js #

/*
  URL: https://learn.coderslang.com/0116-javascript-design-patterns-decorator/
*/

class Headphone {
    constructor(model, color) {
      this.model = model;
      this.color = color;
    }
    getPrice() {
      return 100;
    }
}

class WirelessHeadPhone extends Headphone {
    constructor(model, color) {
      super(model, color);
      this.isWired = false;
    }
    getPrice() {
      return 150;
    }
}

class WaterproofHeadPhone extends Headphone {
    constructor(model, color) {
      super(model, color);
      this.isWaterproof = true;
    }
    getPrice() {
      return 120;
    }
}

class WaterProofAndWirelessHeadphone extends Headphone {
	constructor(model, color) {
		super(model, color);
		this.isWaterproof = true;
		this.isWired = false;
	}
	getPrice() {
		return 170;
	}
}

class BabyEarHeadphone extends Headphone {
	constructor() {
		super(model, color);
		this.size = 'Small';
	}
	getPrice() {
		return 80;
	}
}