Giter Site home page Giter Site logo

javascript-notes's Introduction

JavaScript Notes

Advanced JS Design Patterns

Creational

Are patterns that will creat objects for you instead of instantiating and object directly.

Factory Method

In this example we have a class of points and we can create a cartesian point and a polar point.

 CoordinateSystem = {
	 CARTESIAN: 0,
	 POLAR: 1,
 };

 class Point {
	 constructor(x, y) {
	   this.x = x;
	   this.y = y;
	 }

	 static get factory() {
	   return new PointFactory();
	 }
 }

 class PointFactory {
	 static newCartesianPoint(x, y) {
	   return new Point(x, y);
	 }

	 static newFromPolarPoint(rho, theta) {
	   return new Point(rho * Math.cos(theta), rho * Math.sin(theta));
	 }
}

let point = PointFactory.newFromPolarPoint(5, Math.PI/2);
let point2 = PointFactory.newCartesianPoint(5,6);
console.log(point);
console.log(point2);

Abstract Method

THe abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.

 class Drink {
	consume() {}
 }

 class Tea extends Drink {
	consume() {
	  console.log("This is Tea");
	}
 }

 class Coffee extends Drink {
	consume() {
	  console.log("This is Coffee");
	}
 }

 // Making a Drink Factory

 class DrinkFactory {
	prepare(amount) {}
 }

 class TeaFactory extends DrinkFactory {
	makeTea() {
	  console.log("Tea Created");
	  return new Tea();
	}
 }

 class CoffeeFactory extends DrinkFactory {
	makeCoffee() {
	  console.log("Coffee Created");
	  return new Coffee();
	}
 }

 let teaDrinkFactory = new TeaFactory();
 let tea = teaDrinkFactory.makeTea();
 tea.consume();

Builder

The builder pattern is a design pattern designed to provide a flexible solution to various object creation problems in object-oriented programming.

 class Person {
	constructor() {
	  this.streetAddress = this.postcode = this.city = "";
	  this.companyName = this.position = "";
	  this.annualIncome = 0;
	}
	toString() {
	  return(
		`Person lives at ${this.streetAddress}, ${this.city}, ${this.postcode}
		 and works at ${this.companyName} as a
		 ${this.position} earning ${this.annualIncome}`
	  )
	}
 }

 // Now we need a Person Builder a Person Job Builder, and a Person Address

 class PersonBuilder {
	constructor(person = new Person()){
	   this.person = person;
	}
	get lives() {
	  return new PersonAddressBuilder(this.person);
	}

	get works() {
	  return new PersonJobBuilder(this.person);
	}
	build() {
	  return this.person;
	}
 }

 class PersonJobBuilder extends PersonBuilder {
	constructor(person){
	  super(person);
	}
	at(companyName) {
	  this.person.companyName = companyName;
	  return this;
	}
	asA(position) {
	  this.person.position = position;
	  return this;
	}
	earning(annualIncome) {
	  this.person.annualIncome = annualIncome;
	  return this;
	}
 }

 class PersonAddressBuilder extends PersonBuilder {
	constructor(person) {
	  super(person);
	}
	at(streetAddress){
	  this.person.streetAddress = streetAddress;
		return this;
	}
	withPostcode(postcode) {
	  this.person.postcode = postcode;
	  return this;
	}
	in(city) {
	  this.person.city = city;
	  return this;
	}
 }

 let personBuilder = new PersonBuilder();
 let person = personBuilder.lives
	.at("ABC Road")
	.in("Multan")
	.withPostcode("123123")
	.works.at("Some Company")
	.asA("Engineer")
	.earning("100000000")
	.build();

 console.log(person.toString());
 console.log("\n person: ", JSON.stringify(person));

Prototype

The prototype pattern is a creational design pattern in software development. It is used when the type of objects to creat is determined by a protitypical instance, which is cloned to produce new objects.

	class Car {
	  constructor(name, model) {
		this.name = name;
		this.model = model;
	  }

	  SetName(name) {
		console.log(`${name}`)
	  }

	  clone() {
		  return new Car(this.name, this.model);
	  }
	}

	let car = new Car();
	car.SetName("Audi");

	let car2 = car.clone();
	car2.SetName("BMW");

Singleton

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a classe to one “single” instance. This is useful when exactly one object ie needed to coodinate actions across the system.

 class Singleton {

	constructor () {
	  const instance = this.constructor.instance;

	  if (instance) {
		 return instance;
	  }

	  this.constructor.instance = this;
	}

	say() {
	  console.log("Saying...");
	}
 }

 let s1 = new Singleton();
 let s2 = new Singleton();
 console.log("Are they the same? ", (s1 === s2));

 s1.say();

Structural

This patterns concern class and object composition. They use inheritance to compose interfaces.

Adapter

Is a pattern that allows the interface of an existing class to be used as another interface. It is used to make existing classes work with others without modifying their source code.

 class Calculator1 {
	constructor() {
	  this.operations = function(value1, value2, operation) {
		switch (operation) {
		  case 'add':
			return value1 + value2;
		  case 'sub':
			return value1 - value2;
		}
	  };
	}
 }
 // usage: const c1 = new Calculator1;
 //        c1.operations(1, 2, 'add');

 class Calculator2 {
  constructor() {
	 this.add = function(value1, value2) {
	   return value1 + value2;
	 };

	 this.sub = function(value1, value2) {
	   return value1 = value2;
	 }
  }
 }
 // usage: const c2 = new Calculator2;
 //        c2.add(1, 2);

 class CalcAdapter {
	constructor () {
	  const cal2 = new Calculator2();
	  this.operations = function(value1, value2, operation) {
		switch (operation) {
		  case 'add':
			return cal2.add(value1, value2);
		  case 'sub':
			return cal2.sub(value1, value2);
		}
	  };
	}
 }

 const adaptedCalc = new CalcAdapter();
 console.log(adaptedCalc.operations(1, 2, 'add'));

Bridge

Bridge is a structural design pattern that lets you split a large class of a set of closely related classes into two separate hierarchies - abstraction and implementation -which can be developed independently of each other.

 class VectorRenderer {
	renderCircle(radius) {
	  console.log(`Drawing a circle of radius ${radius}`);
	}
 }

 class RasterRenderer {
	renderCircle(radius) {
	  console.log(`Drawing pixels for circle of radius ${radius}`);
	}
 }

 class Shape {
	constructor(renderer) {
	  this.renderer = renderer;
	}
 }

 class Circle extends Shape {
	constructor(renderer, radius) {
	  super(renderer);
	  this.radius = radius;
	}
	draw() {
	  this.renderer.renderCircle(this.radius);
	}
	resize(factor) {
	  this.radius *= factor;
	}
 }

 const raster = new RasterRenderer();
 const vector = new VectorRenderer();
 
 const circle = new Circle(vector, 5);

 circle.draw();
 circle.resize(2);
 circle.draw();

Composite

The composite pattern describes a group of objects that are treated the same way as a single instance of the same type of object.

 class Employer {
	constructor(name, role) {
	  this.name = name;
	  this.role = role;
	}
	print() {
	  console.log(`Name: ${this.name} | Role: ${this.role}`);
	}
 }

 class EmployerGroup{
	constructor(name, composite=[]) {
	  console.log(name);
	  this.name = name;
	  this.composites = composite;
	}

	print() {
	  console.log(this.name);
	  this.composites.forEach(emp => emp.print());
	}
 }

 let bob = new Employer("bob", "developer on proj1");
 let anne = new Employer("anne", "developer on proj1 and proj2");

 let groupDevelopers = new EmployerGroup("Developers", [bob, anne]);

Decorator

The decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class.

 class Shape {
	constructor(color) {
	  this.color = color;
	}
 }

 class Circle extends Shape {
	constructor(radius = 0) {
	  super();
	  this.radius = radius;
	}
	resize(factor) {
	  this.radius *= factor;
	}
	toString() {
	  return `A circle ${this.radius}`;
	}
 }

 class ColoredShape extends Shape {
	constructor(shape, color) {
	  super();
	  this.shape = shape;
	  this.color = color;
	}
	toString() {
	  return `${this.shape.toString()} has the color ${this.color}`;
	}
 }

 let circle = new Circle(2);
 console.log(circle);

 let redCircle = new ColoredShape(circle, "red");
 console.log(redCircle.toString());

Facade

The facade pattern (also spelled façade) is a software-design pattern commonly used in object-oriented programming. Analogous to a facade in architecture, a facade is an object that serves as a front-facing interface masking more complex underlying or structural code.

 class CPU {
	freeze() { console.log("Freezed....") }
	jump(position) { console.log ("Go.....")}
	execute() { console. log("Run....") }
 }

 class Memory {
	load(position, data) { console.log("Load.....") }
 }

 class HardDrive {
	read(lba, size) { console.log("Ready....") }
 }

 class ComputerFacade {
	constructor() {
	  this.processor = new CPU();
	  this.ram = new Memory();
	  this.hd = new HardDrive();
	}

	start() {
	  this.processor.freeze();
	  this.ram.load(this.BOOT_ADDRESS, this.hd.read(this.BOOT_SECTOR, this.SECTOR_SIZE));
	  this.processor.jump(this.BOOT_ADDRESS);
	  this.processor.execute();
	}
 }


 let computer = new ComputerFacade();
 computer.start();

Flyweight

A flyweight is an object that minimizes memory usage by sharing as much data as possible with other similar objects.

		 class User {
		   constructor(fullName) {
			   this.fullName = fullName;  
		   }
		 }

		 class User2 {
		   constructor(fullName) {
			   let getOrAdd = function(s) {
			   let idx = User2.strings.indexOf(s);
				 if (idx !== -1) return idx;
				 else {
				   User2.strings.push(s);
				   return User2.strings.length - 1;
				 }
			   };
			   this.names = fullName.split(' ').map(getOrAdd);
		   }
		 }

		 User2.strings = [];

		 function getRandomInt(max) {
		   return Math.floor(Math.random() * Math.floor(max));
		 }

		 let randomString = function() {
		   let result = [];
		   for (let x = 0; x < 10; ++x)
			 result.push(String.fromCharCode(65 + getRandomInt(26)));

		   return result.join('');
		 }


		 // -----

		 let users = [];
		 let users2 = [];
		 let firstNames = [];
	     let lastNames = [];

		 for (let i = 0; i < 100; ++i) {
		   firstNames.push(randomString());
		   lastNames.push(randomString());
		 }

		 // making 10k users
		 for (let first of firstNames) {
		   for (let last of lastNames) {
			 users.push(new User(`${first} ${last}`));
			 users2.push(new User2(`${first} ${last}`));
		   }
		 }

		console.log(`10k users take up ~${JSON.stringify(users).length} chars`);

		let users2length = [users2, User2.strings]
			.map(x => JSON.stringify(x).length)
			.reduce((x,y) => x+y);

		console.log(`10k flyweight users take ~${users2length} chars`);

Proxy

By using Proxy, a class can represent the functionality of another class.

The proxy pattern is a software design pattern. A proxy, in its most general form, is a class functioning as an interface to something else.

 class Percentage {
	constructor(percent) {
	  this.percent = percent;
	  }

	toString() {
	  return `${this.percent}%`;
	}

	valueOf() {
	  return this.percent / 100;
	}
 }

 let fivePercent = new Percentage(5);
 console.log(fivePercent.toString());
 console.log(`5% of 50 is ${50 * fivePercent}`);

Behavioral

In software engineering, behavioral design patterns are design patterns that identify common communication patterns among objects. By doing so, these patterns increase flexibility in carrying out communication.

Chain of Responsibility

In object-oriented design, the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects.

 class Creature {
	constructor(name, attack, defense) {
	  this.name = name;
	  this.attack = attack;
	  this.defense = defense;
	}
	toString() {
	  return `${this.name} (${this.attack}/${this.defense})`;
	}
 }

 class CreatureModifier {
	constructor(creature) {
	  this.creature = creature;
	  this.next = null;
	}

	add(modifier) {
	  if (this.next) this.next.add(modifier);
	  else this.next = modifier;
	}

	handle() {
	  if (this.next) this.next.handle();
	}
 }

 class NoBonusesModifier extends CreatureModifier {
	constructor(creature) {
	  super(creature);
	}
	handle() {
	  console.log("No bonuses for you!");
	}
 }

 class DoubleAttackModifier extends CreatureModifier {
	constructor(creature) {
	  super(creature)
	}
	handle() {
	  console.log(`Doubling ${this.creature.name}'s attack`);
	  this.creature.attack *= 2;
	  super.handle();
	}
 }

 class IncreaseDefenseModifier extends CreatureModifier {
	constructor(creature) {
	  super(creature);
	}

	handle() {
	  if (this.creature.attack <= 2) {
		console.log(`Increasing ${this.creature.name}'s defense`);
		this.creature.defense += 1;
	  }

	super.handle();
  }
 }



 let dragon = new Creature("Dragon", 1, 1);
 console.log(dragon.toString());

 let root = new CreatureModifier(dragon);
 root.add(new DoubleAttackModifier(dragon));
 root.add(new IncreaseDefenseModifier(dragon));
 root.handle();

 console.log(dragon.toString());

 root.add(new DoubleAttackModifier(dragon));
 root.add(new IncreaseDefenseModifier(dragon));
 root.handle();

 console.log(dragon.toString());

Command

It creates objects which encapsulate actions in objects.

In object-oriented programming, the command pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time. This information includes the method name, the object that owns the method and values for the method parameters.

 class BankAccount {
	constructor(balance = 0) {
	  this.balance = balance;
	}

	deposit(amount) {
	  this.balance += amount;
	  console.log(`Deposited ${amount} - Total Balance ${this.balance}`);
	}

	withdraw(amount) {
	  if (this.balance - amount >= BankAccount.overdraftLimit) {
		this.balance -= amount;
		console.log("Withdraw");
	  }
	}

	toString() {
	  return `Balance ${this.balance}`;  
	}
 }

 BankAccount.overdraftLimit = -500;

 // commands
 let Action = Object.freeze({
	deposit: 1,
	withdraw: 2,
 })

 class BankAccountCommand {
	constructor(account, action, amount) {
	  this.account = account;
	  this.action = action;
	  this.amount = amount;
	}

	call() {
	  switch (this.action) {
		case Action.deposit:
		  this.account.deposit(this.amount);
		  break;
		case Action.withdraw:
		  this.account.withdraw(this.amount);
		  break;
	  }
	}

	undo() {
	  switch (this.action) {
		case Action.deposit:
		  this.account.withdraw(this.amount);
		  break;
		case Action.withdraw:
		  this.account.deposit(this.amount);
		  break;
	  }
	}
 }

 // usage

 let bankAccount = new BankAccount(100);
 let cmd = new BankAccountCommand(bankAccount, Action.deposit, 50);

 console.log(bankAccount.toString());
 
 cmd.call();
 console.log(bankAccount.toString());

 cmd.undo();
 console.log(bankAccount.toString());

Iterator

Iterator accesses the elements of an object without exposing its underlying representation.

In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container’s elements.

We will be taking an example of an array in which we print the values of an array and then by using an iterator we print its value backwords.

 class Stuff {
	 constructor() {
	   this.a = 100;
	   this.b = 200;
	 }

	[Symbol.iterator](){
	  let i = 0;
	  let self = this;
	  return {
		next: function() {
		  return {
			done: i > 1,
			value: self[i++ === 0 ? 'a' : 'b']
		  };
		}
	  }
	}

	get backwards() {
	  let i = 0;
	  let self = this;
	  return {
		next: function() {
		  return {
		   done: i > 1,
		   value: self[i++ === 0 ? 'b' : 'a']
		  };
		},
	  // make iterator iterable
	  [Symbol.iterator]: function () { return this; }
	  }
	}
 }

 // using it

 let values = [100, 200, 300];

 for (let i in values) {
	console.log(`Element at pos ${i} is ${values[i]}`);
 }

 for (let v of values) {
	console.log(`Values is ${v}`);
 }

 let stuff = new Stuff();

 for (let item of stuff)
	console.log(`${item}`);

 for (let item of stuff.backwards)
	console.log(`${item}`);

Mediator

The mediator pattern adds a third-party object to control the interaction between two objects. It allows loose coupling between classes by being the only class that has detailed knowledge of their methods.

The mediator pattern defines an object that encapsulates how a set of objects interact. This pattern is considered to be a behavioral pattern due to the way it can alter the program’s running behavior. In object-oriented programming, programs often consist of many classes.

We will be using an example of a person using a chat room. Here, a chatroom acts as a mediator between two people communicating.

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

	receive(sender, message) {
	  let s = `${sender}: ${message}`;
	  console.log(`[${this.name}'s chat session] ${s}`);
	  this.chatLog.push(s);
	}

	say(message) {
	  this.room.broadcast(this.name, message);
	}

	pm(who, message) {
	  this.room.message(this.name, who, message);  
	}
 }

 class ChatRoom {
	constructor() {
	  this.people = [];
	}

	broadcast(source, message) {
	  for (let p of this.people)
		if (p.name !== source) p.receive(source, message);
	}

	join(p) {
	  let joinMsg = `{p.name} joins the chat`;
	  this.broadcast("room", joinMsg);
	  p.room = this;
	  this.people.push(p);
	}

	message(source, destination, message) {
	  for (let p of this.people)
		if (p.name === destination) p.receive(source, message);
	}
 }

 let room = new ChatRoom();

 let Alice = new Person("Alice");
 let Bob = new Person("Bob");

 room.join(Alice);
 room.join(Bob);
 Bob.say("Hello!!!");

 let doe = new Person("Doe");
 room.join(doe);
 doe.say("Hello everyone!");

Memento

Memento restores an object to its previous state.

The memento pattern is a software design pattern that provides the ability to restore an object to its previous state. The memento pattern is implemented with three objects: the originator, a caretaker and a memento.

We will be taking an example of a bank account in which we store our previous state and will have the functionality of undoing.

 class Memento {
	constructor(balance) {
	  this.balance = balance;
	}
 }

 class BankAccount {
	constructor(balance = 0) {
	  this.balance = balance;
	}
	deposit(amount) {
	  this.balance += amount;
	  return new Memento(this.balance);
	}
	restore(m) {
	  this.balance = m.balance;
	}
	toString() {
	  return `Balance: ${this.balance}`;
	}
 }

 let bankAccount = new BankAccount(100);

 console.log(bankAccount.toString());
 let m1 = bankAccount.deposit(50);
 console.log(bankAccount.toString());

 bankAccount.restore(m1);
 console.log(bankAccount.toString());

Observer

It allows a number of observer objects to see an event.

The observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

We will be taking an example of a person in which if a person falls ill, it will display a notification.

 class Event {
	constructor() {
	  this.handlers = new Map();
	  this.count = 0;
	}

	subscribe(handler) {
	  this.handlers.set(++this.count, handler);
	  return this.count;
	}

	unsubscribe(idx) {
	  this.handlers.delete(idx);
	}

	fire(sender, args) {
	  this.handlers.forEach((v, k) => v(sender, args));
	}
 }

 class FallsIllArgs {
	constructor(address) {
	  this.address = address;
	}
 }

 class Person {
	constructor(address) {
	  this.address = address;
	  this.fallsIll = new Event();
	}

	catchCold() {
	  this.fallsIll.fire(this, new FallsIllArgs(this.address));
	}
 }

 // how to use it

 let person = new Person("ABC road");

 let sub = person.fallsIll.subscribe((s, a) => {
	console.log(`A doctor has been called to ${a.address}`);
 });

 person.catchCold();
 person.catchCold();
 
 person.fallsIll.unsubscribe(sub);
 person.catchCold();

Visitor

It adds operations to objects without having to modify them.

The visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures.

We will be taking an example of NumberExpression in which it gives us the result of the given expression.

 class NumberExpression {
	constructor(value) {
	  this.value = value;  
	}
	print(buffer) {
	  buffer.push(this.value.toString());
	}
 }

 class AdditionExpression {
	constructor(left, right) {
	  this.left = left;
	  this.right = right;
	}
	print(buffer) {
	  buffer.push('(');
	  this.left.print(buffer);
	  buffer.push('+');
	  this.right.print(buffer);
	  buffer.push(')');
	}
 }

 // That's how we will use this,
 // given expression => 5 + (1+9)

 let e = new AdditionExpression(
	new NumberExpression(5),
	new AdditionExpression(
	  new NumberExpression(1),
	  new NumberExpression(9)
	)
 );

 let buffer = [];
 e.print(buffer);
 console.log(JSON.stringify(buffer.join('')));

Strategy

It allows one of the algorithms to be selected in certain situations.

The strategy pattern is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.

We will take an example in which we have a text processor that will display data based on strategy(HTML or Markdown).

 let OutputFormat = Object.freeze({
	markdown: 0,
	html: 1,
 });

 class ListStrategy {
	start(buffer) {}
	end(buffer) {}
	addListem(buffer, item) {}
 }

 class MarkdownListStrategy extends ListStrategy {
	addListItem(buffer, item) {
	  buffer.push(` * ${item}`);
	}
 }

 class HtmlListStrategy extends ListStrategy {
	start(buffer) {
	  buffer.push("<ul>");
	}
	end(buffer) {
	  buffer.push("</ul>");
	}
	addListItem(buffer, item) {
	  buffer.push(`  <li>${item}</li>`);  
	}
 }

 class TextProcessor {
	constructor(outputFormat) {
	  this.buffer = [];
	  this.setOutputFormat(outputFormat);  
	}
	setOutputFormat(format) {
	  switch (format) {
		case OutputFormat.markdown:
		  this.listStrategy = new MarkdownListStrategy();
		  break;
		case OutputFormat.html:
		  this.listStrategy = new HtmlListStrategy();
		  break;
	  }
	}
	appendList(items) {
	  this.listStrategy.start(this.buffer);
	  for (let item of items) {
		this.listStrategy.addListItem(this.buffer, item);
	  }
	  this.listStrategy.end(this.buffer);
	}
	clear() {
	  this.buffer = [];
	}
	toString() {
	  return this.buffer.join("\n");
	}
 }

 let tp = new TextProcessor();

 tp.setOutputFormat(OutputFormat.markdown);
 tp.appendList(["one", "two", "three"]);
 console.log(tp.toString());

 tp.clear();
 tp.setOutputFormat(OutputFormat.html);
 tp.appendList(["one", "two", "three"]);
 console.log(tp.toString());

State

It alters the behavior of an object when its internal state changes.

The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. This pattern is close to the concept of finite-state machines.

We will be taking an example of a light switch in which if we turn on or off the switch, its state changes.

 class State {
	constructor() {
	  if (this.constructor === State) throw new Error("abstract!");
	}

	on(sw) {
	  console.log("Light is already on.");
	}

	off(sw) {
	  console.log("Light is already off.");
	}	
 }
 
 class OnState extends State {
	constructor() {
	  super();
	  console.log("Light turned on.");
	}
	off(sw) {
	  console.log("Turning light of...");
	  sw.state = new OffState();
	}
 }

 class OffState extends State {
	constructor() {
	  super();
	  console.log("Light turned off.");
	}
	off(sw) {
	  console.log("Turning light on...");
	  sw.state = new OnState();
	}
 }

 class Switch {
	constructor() {
	  this.state = new OffState();  
	}

	on() {
	  this.state.on(this);
	}

	off() {
	  this.state.off(this);
	}
 }


 let mySwitch = new Switch();
 mySwitch.on();
 mySwitch.off();

Template

It defines the skeleton of an algorithm as an abstract class, that how should it be performed.

Template Method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps.

We will be taking an example of a chess game,

  class Game {
	constructor(numberOfPlayers) {
	  this.numberOfPlayers = numberOfPlayers;
	  this.currentPlayer = 0;
	}

	run() {
	  this.start();
	  while (!this.haveWinner) {
		this.takeTurn();
	  }
	  console.log(`Player ${this.winningPlayer} wins.`);
	}

	start() {}

	get haveWinner() {}

	takeTurn() {}

	get winningPlayer() {}
  }

  class Chess extends Game {
	constructor() {
	  super(2);
	  this.maxTurns = 10;
	  this.turn = 1;
	}

	start() {
	  console.log(`Starting a game of chess with ${this.numberOfPlayers} players.`);  
	}

	get haveWinner() {
	  return this.turn === this.maxTurns;
	}

	takeTurn() {
	  console.log(`Turn ${this.turn++} taken by player ${this.currentPlayer}.`);

	  this.currentPlayer = (this.currentPlayer + 1) % this.numberOfPlayers;
	}

	get winningPlayer() {
	  return this.currentPlayer;
	}

  }

let chess = new Chess();
chess.run();

Source

https://medium.com/dhiwise/advanced-javascript-design-patterns-6812f3286585

Await inside loops

What will be the output of this snippet?

const arr = [1 ,2 , 3 , 4];
let resValue = 1;

const incAfter1Sec = () => new Promise((res, rej) => {
  setTimeout(() => { res(resValue++) }, 1000);
});

const testing  = async () => {
  console.log('🚀 Start')

  arr.forEach(async (each) => {
    const val = await incAfter1Sec()
    console.log("🚀 each", val)

   })

  console.log('🚀 End');

}

testing();

What about instead of a forEach, mapping?

const arr = [1 ,2 , 3 , 4];
let resValue = 1;

const incAfter1Sec = () => new Promise((res, rej) => {
  setTimeout(() => { res(resValue++) }, 1000);
});

const testing  = async () => {
  console.log('🚀 Start')

  arr.map(async (each) => {
    const val = await incAfter1Sec()
    console.log("🚀 each", val)

   })

  console.log('🚀 End');

}

testing();

In simple terms, each (from the code) is called on separate function that is syncrhonous. forEach (and map) expects a synchronous function and does not wait for promises. This can be explained by the concept of `generators`.

`each` iteration end calls the `next()` method, `yield` the value and exit, then, call `next()` again, and since `next()` accepts only synchronous stuff, promises don`t work as intended when we use await.

The `solution`, simply use a for loop:

const arr = [1 ,2 , 3 , 4];
let resValue = 1;

const incAfter1Sec = () => new Promise((res, rej) => {
  setTimeout(() => { res(resValue++) }, 1000);
});

const testing  = async () => {
  console.log('🚀 Start')

  for (let i = 0; i < arr.length ; i++) {
	    console.log("🚀 each", i);
	    await incAfter1Sec()

    }

  console.log('🚀 End');
}

testing();

It could be also written in this fashion:

const arr = [1 ,2 , 3 , 4];
let resValue = 1;

const incAfter1Sec = () => new Promise((res, rej) => {
  setTimeout(() => { res(resValue++) }, 1000);
});

const testing  = async () => {
  console.log('🚀 Start')

  for (const i in arr) {
	    console.log("🚀 each", i);
	    await incAfter1Sec()

    }

  console.log('🚀 End');
}

testing();

What is: Functional Programming [TODO]

Source

https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0#.jddz30xy3

Curry or Partial Application?

Definitions

Application

The process of applying a function to its arguments in order to produce a return value.

Partial Application

The process of applying a function to some of its arguments. The partially applied function gets returned for later use. In other words, a function that takes a function with multiple parameters and returns a function with fewer parameters. Partial application fixes (partially applies the function to) one or more arguments inside the returned function, and the returned function takes the remaining parameters as arguments in order to complete the function application.

Curry

A function that takes a function with multiple parameters as input and returns a function with exactly one parameter.

Source

https://medium.com/javascript-scene/curry-or-partial-application-8150044c78b8#.13tj19278

What is: Function Composition

Function composition

Is the process of combining two or more functions to produce a new function. Composing funcitons together is like snapping together a series of pipes for our data to flow throug.

The composition of functions `f` and `g` can be defined as `f(g(x))`, which evaluates from the inside out, right to left. In other words:

  1. `x`
  2. `g`
  3. `f`

Example of what is

You want to do the following:

  1. split the name into an array on spaces
  2. map the name to lower case
  3. join with dashes
  4. encode the URI component
const toSlug = input => encodeURIComponent(
  input.split(' ')
  .map(str => str.toLowerCase())
  .join('-')
  );
console.log(toSlug('JS Cheerleader'));  // 'js-cheerleader'

Not bad, but what about do it more readable?

 const toSlug = input => encodeURIComponent(
   join('-')(
     map(toLowercase)(
	split(' ')(
	  input
	)
	)
     )
 )

 console.log(toSlug('JS Cheerleader')); // 'js-cheerleader'

It looks even harder to read, but wait a bit…

If we use composable forms of common utilities, like.

const curry = fn => (...args) => fn.bind(null, ...args);
const map = curry((fn, arr) => arr.map(fn));
const join = curry((str, arr) => arr.join(str));
const toLowerCase = str => str.toLowerCase();

const split = curry((splitOn, str) => str.split(splitOn));

Or even production-tested versions available from Loadash/fp or ramda. You can import like this:

import { curry, map, join, split } from 'lodash/fp';
// ...or like this...
const curry = require('lodash/fp/curry');
const map = require('lodash/fp/map');

To be honest, this implementation of curry is a little bit lazy, a real curry would always produce a unary function. Instead, this is a simple partial application. For the porposes of this demo, it will work interchangeable.

Going back to our `toSlug()` implementation, it looks like a lot of nesting, and a bit confusing to read. We can flatten the nesting with a function that will compose these functions automatically, meaning that it will take the output from one function and automatically patch it to input of the next function until it spits out the final value.

Come to think of it we have an extras utility that sounds like something like that. It takes a list of values and applies a function to each of those values, accumulating a single result. The values themselves can be functions. The functions is called `reduce()`, but to match the compose behavior above, we need it to reduce right to left, instead of left to right.

Good thing there’s a `reduceRight()` that does exactly what we’re looking for:

const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);

Like `.reduce()`, the array `.reduceRight()` method takes a reducer function and an initial value (`x`). We iterate over the array functions (from right to left), applying each in turn to the accumulated value (`v`).

With compose, we can rewrite our composition above without the nesting:

const toSlug = compose(
  encodeURIComponent,
  join('-'),
  map(toLowerCase),
  split(' ')
);

console.log(toSlug('JS Cheerleader')); // 'js-cheerleader'

Of course, `compose()` comes with a loadash/fp or ramda as well:

import { compose } from 'lodash/fp';
// or
const compose = require('lodash/fp/compose');

Compose is great when you’re thinking in terms of the mathematical form of composition, inside out… but what if you want to think in terms of the sequence from left to right?

There’s another form commonly called `pipe()`. Lodash calls it `flow()`:

const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);

const fn1 = s => s.toLowerCase();
const fn2 = s => s.split('').reverse().join('');
const fn3 = s => s + '!'

const newFunc = pipe(fn1, fn2, fn3);
const result = newFunc('Time'); // emit!

Notice the implementation is exactly the same as `compose()`, except that we’re using `.reduce()` instead of `.reduceRight()`, which reduces left to right instead of right to left.

Let’s look at our `toSlug()` function implemented with `pipe()`:

const toSlug = pipe(
  split(' '),
  map(toLowerCase),
  join('-'),
  encodeURIComponent
);

console.log(toSlug('JS Cheerleader')); // 'js-cheerleader'

For me, this is much easier to read.

Hardcore functional programmers define their entire application in terms of function compositions. I use it frequently to eliminate the need for temporary variables. Look at the `pipe()` version of `toSlug()` carefully and you might notice something special.

In imperative programming, when you’re performing transformations on some variable, you’ll find references to the variable in each step of the transformation. The `pipe()` implementation above is written in a points-free style, which means that it does not identify the arguments on which it operates at all.

I frequently use pipes in things like unit tests and Redux state reducers to eliminate the need for intermediary variables which exist only to hold transient values between one operation and the next.

That may sound weird at first, but as you get practice with it, you’ll find that in functional programming, you’re working with very abstract, generalized functions in which the names of things don’t matter so much. Names just get in the way. You may start to think of variables as unnecessary boilerplate.

That said, I’m of the opinion that points-free style can be taken too far. It can become too dense, and harder to understand, but if you get confused, here’s a little tip… you can tap into the flow to trace what’s going on:

const trace = curry((label, x) => {
  console.log(`== ${ label }:  ${ x }`);
  return x;
});

Here’s how you use it:

  const toSlug = pipe(
  trace('input'),
  split(' '),
  map(toLowerCase),
  trace('after map'),
  join('-'),
  encodeURIComponent
);

console.log(toSlug('JS Cheerleader'));
// '== input:  JS Cheerleader'
// '== after map:  js,cheerleader'
// 'js-cheerleader'

`trace()` is just a special form of the more general `tap()`, which lets you perform some action for each value that flows through the pipe. Get it? Pipe? Tap? You can write `tap()` like this:

const tap = curry((fn, x) => {
  fn(x);
  return x;
});

Now you can see how `trace()` is just a special-cased `tap()`:

const trace = label => {
  return tap(x => console.log(`== ${ label }:  ${ x }`));
};

You should be starting to get a sense of what functional programming is like, and how partial application & currying collaborate with function composition to help you write programs which are more readable with less boilerplate.

Source:

https://medium.com/javascript-scene/master-the-javascript-interview-what-is-function-composition-20dfb109a1a0

What is: Difference Between Class & Prototypal Inheritance

Class Inheritance

A Class is like a blueprint - a description of the object to be created. Classes inherit from classes and create subclass relationships: hierarchical class taxonomies.

Instances are typically instantiated via constructor functions with the **new** keyword. Class inheritance may or may not use the **class** keyword from ES6. Classes as you may know them from languages like Java don’t technically exist in Javascript. Constructor functions are used, instead. The ES6 **class** keyword desugars to a constructor function:

class Foo {};
console.log(typeof Foo);
function

In JS, class inheritance is implemented on top of prototypal inheritance, but that does not mean that it does the same thing:

JS class inheritance uses the prototype chain o wire the child `Constructor.prototype` to the parent `Constructor.prototype` for delegation. Usually, the `super()` constructor is also called. Those steps form **single-ancestor parent/child hierarchies** and **create the tightest coupling available in OO design**.

Prototypal Inheritance

A prototype is a working object instance. Objects inherit directly from other objects.

Instances may be composed from many different source objects, allowing for easy selective inheritance and flat **Prototype** delegation hierarchy. In other words, class taxonomies are not an automatic side-effect of prototypal OO: a critical distinction.

Instances are typically instantiated via factory functions, object literals, or `Object.create()`.

Why does this Matter?

Inheritance is fundamentally a code reuse mechanism: A way for different kinds of objects to share code. The way that you share code matters because if you get it wrong, it can create a lot of problems, specifically:

**Class inheritance creates parent/child objects taxonomies as side-effect**

Those are virtually impossible to get right for all new use cases, and widespread use of a base class leads to the **fragile base class problem**, which makes them difficult to fix when you get them wrong. In fact, class inheritance causes many well known problems in OO design:

  • The tight coupling problem (class inheritance is the tightest coupling avaiable in oo design), which leads to…
  • The fragile base class problem
  • Inflexible hierarchy problem (eventually, all evolving hierarchies are wrong for new uses)
  • The duplication by necessity problem (due to inflexible hierarchies, new use cases are often shoe-horned in by duplicating, rather than adapting existing code)
  • The Gorilla/banana problem (What you wanted was a banana, but what you got was a gorilla holding the banana, and the entire jungle)

The solution to all of these problems:

** Favor object composition over class inheritance. **

~ The Gang of Four, “Design Patterns: Elements of Reusable Object Oriented Software”

Three Different Kinds of Prototypal Inheritance

Before the three

Before we dive into the other kinds of inheritance, let’s take a closer look at what I mean by class inheritance:

 // Class Inheritance Example
 // NOT RECOMMENDED. Use object composition, instead.
  class GuitarAmp {
   constructor ({ cabinet = "spruce", distortion = "1", volume = "0" } = {}) {
     Object.assign(this, {
	  cabinet, distortion, volume
	});
     }
   }

 class BassAmp extends GuitarAmp {
   constructor (options = {}) {
     super(options);
     this.lowCut = options.lowCut;
     }
   }

 class ChannelStrip extends BassAmp {
   constructor (options = {}) {
     super(options);
     this.inputLevel = options.inputLevel;
     }
   }

 const myAmp = new BassAmp();
 const actualAmp = Object.keys(myAmp);
 const expectedAmp = ["cabinet", "distortion", "volume", "lowCut"];

 console.log("1.", actualAmp, expectedAmp, " instance should inherit props from GuitarAmp and BassAmp");

 const myStrip = new ChannelStrip();
 const actualStrip = Object.keys(myStrip);
 const expectedStrip = ["cabinet", "distortion", "volume", "lowCut", "inputLevel"];

console.log("2.", actualStrip, expectedStrip, " instance should inherit props from GuitarAmp, BassAmp and ChannelStrip");
1. [ 'cabinet', 'distortion', 'volume', 'lowCut' ] [ 'cabinet', 'distortion', 'volume', 'lowCut' ]  instance should inherit props from GuitarAmp and BassAmp
2. [ 'cabinet', 'distortion', 'volume', 'lowCut', 'inputLevel' ] [ 'cabinet', 'distortion', 'volume', 'lowCut', 'inputLevel' ]  instance should inherit props from GuitarAmp, BassAmp and ChannelStrip

`BassAmp` inherits from `GuitarAmp`, and `ChannelStrip` inherits from `BassAmp` & `GuitarAmp`. This is an example of how OO design goes wrong. A channel strip isn’t actually a type of guitar amp, and doesn’t actually need a cabinet at all. A better option would be to create a new base class that both the amps and the channel strip inherits from, but even that has limitations.

Eventually, the new shared base class strategy breaks down, too.

There’s a better way. You can inherit just the stuff you really need using object composition:

// Composition Example

const distortion = { distortion: 1 };
const volume = { volume: 1 };
const cabinet = { cabinet: "maple" };
const lowCut = { lowCut: 1 };
const inputLevel = { inputLevel: 1 };

const GuitarAmp = (options) => {
  return Object.assign({}, distortion, volume, cabinet, options);
};

const BassAmp = (options) => {
  return Object.assign({}, lowCut, volume, cabinet, options);
};

const ChannelStrip = (options) => {
  return Object.assign({}, inputLevel, lowCut, volume, options);
};


  const msgGuitarAmp = "should have distortion, volume, and cabinet";
  const levelGuitarAmp = 2;
  const cabinetGuitarAmp = "vintage";

  const actualGuitarAmp = GuitarAmp({
    distortion: levelGuitarAmp,
    volume: levelGuitarAmp,
    cabinet: cabinetGuitarAmp
  });
  const expectedGuitarAmp = {
    distortion: levelGuitarAmp,
    volume: levelGuitarAmp,
    cabinet: cabinetGuitarAmp,
  };

  console.log("1.", actualGuitarAmp, expectedGuitarAmp, msgGuitarAmp);

  const msgBassAmp = "should have volume, lowCut, and cabinet";
  const levelBassAmp = 2;
  const cabinetBassAmp = "vintage";

  const actualBassAmp = BassAmp({
    lowCut: levelBassAmp,
    volume: levelBassAmp,
    cabinet: cabinetBassAmp
  });
  const expectedBassAmp = {
    lowCut: levelBassAmp,
    volume: levelBassAmp,
    cabinet: cabinetBassAmp,
  };

  console.log("2.", actualBassAmp, expectedBassAmp, msgBassAmp);

const msgChannel = "should have inputLevel, lowCut, and volume";
const levelChannel = 2;

const actualChannel = ChannelStrip({
    inputLevel: levelChannel,
    lowCut: levelChannel,
    volume: levelChannel,
  });
  const expectedChannel = {
    inputLevel: levelChannel,
    lowCut: levelChannel,
    volume: levelChannel,
  };

console.log("2.", actualChannel, expectedChannel, msgChannel);
1. { distortion: 2, volume: 2, cabinet: 'vintage' } { distortion: 2, volume: 2, cabinet: 'vintage' } should have distortion, volume, and cabinet
2. { lowCut: 2, volume: 2, cabinet: 'vintage' } { lowCut: 2, volume: 2, cabinet: 'vintage' } should have volume, lowCut, and cabinet
2. { inputLevel: 2, lowCut: 2, volume: 2 } { inputLevel: 2, lowCut: 2, volume: 2 } should have inputLevel, lowCut, and volume
undefined

If you look carefully, you might see that we’re being much more specific about which objects get which properties because with composition, we can. It wasn’t really an option with class inheritance. When you inherit from a class, you get everything, even if you don’t want it.

At this point, you may be thinking to yourself, “that’s nice, but where are the prototypes?”

To understand that, you have to understand that there are three different kinds of prototypal OO.

Concatenative inheritance

The process of inheriting features directly from one object to another by copying the source objects properties. In JavaScript, source prototypes are commonly referred to as mixins. Since ES6, this feature has a convenience utility in JavaScript called `Object.assign()`. Prior to ES6, this was commonly done with Underscore/Lodash’s `.extend()` jQuery’s `$.extend()`, and so on… The composition example above uses concatenative inheritance.

Prototype delegation

In JavaScript, an object may have a link to a prototype for delegation. If a property is not found on the object, the lookup is delegated to the delegate prototype, which may have a link to its own delegate prototype, and so on up the chain until you arrive at `Object.prototype`, which is the root delegate. This is the prototype that gets hooked up when you attach to a `Constructor.prototype` and instantiate with `new`. You can also use `Object.create()` for this purpose, and even mix this technique with concatenation in order to flatten multiple prototypes to a single delegate, or extend the object instance after creation.

The JS prototype chain:

+---------------------+       +----------------------+	       +---------------------+
|       George        |       |      Prototype       +--------+   Object.prototype  |
| name	               +-------+  hello()             |	       | ...                 |
| [[Prototype]]       |       |  [[Prototype]]       |	       |                     |
|                     |       |                      |	       |                     |
+---------------------+       +----------------------+	       +---------------------+

Functional inheritance

In JavaScript, any function can create an object. When that function is not a constructor (or `class`), it’s called a factory function. Functional inheritance works by producing an object from a factory, and extending the produced object by assigning properties to it directly (using concatenative inheritance). Douglas Crockford coined the term, but functional inheritance has been in common use in JavaScript for a long time.

As you’re probably starting to realize, concatenative inheritance is the secret sauce that enables object composition in JavaScript, which makes both prototype delegation and functional inheritance a lot more interesting.

When most people think of prototypal OO in JavaScript, they think of prototype delegation. By now you should see that they’re missing out on a lot. Delegate prototypes aren’t the great alternative to class inheritance — object composition is.

Why Composition is Immune to the Fragile Base Class Problem

To understand the fragile base class problem and why it doesn’t apply to composition, first you have to understand how it happens:

`A` is the base class

`B` inherits from `A`

`C` inherits from `B`

`D` inherits from `B`

`C` calls `super`, which runs code in `B`. `B` calls `super` which runs code in `A`.

`A` and `B` contain unrelated features needed by both `C` & `D`. `D` is a new use case, and needs slightly different behavior in `A`’s init code than `C` needs. So the newbie dev goes and tweaks `A`’s init code. `C` breaks because it depends on the existing behavior, and `D` starts working.

What we have here are features spread out between `A` and `B` that `C` and `D` need to use in various ways. `C` and `D` don’t use every feature of `A` and `B`… they just want to inherit some stuff that’s already defined in `A` and `B`. But by inheriting and calling `super`, you don’t get to be selective about what you inherit. You inherit everything:

** …the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.” ~ Joe Armstrong — “Coders at Work **

With Composition

Imagine you have features instead of classes:

feat1, feat2, feat3, feat4

`C` needs `feat1` and `feat3`, `D` needs `feat1`, `feat2`, `feat4`:

const C = compose(feat1, feat3);
const D = compose(feat1, feat2, feat4);

Now, imagine you discover that `D` needs slightly different behavior from `feat1`. It doesn’t actually need to change `feat1`, instead, you can make a customized version of `feat1` and use that, instead. You can still inherit the existing behaviors from `feat2` and `feat4` with no changes:

const D = compose(custom1, feat2, feat4);  

And `C` remains unaffected.

The reason this is not possible with class inheritance is because when you use class inheritance, you buy into the whole existing class taxonomy.

If you want to adapt a little for a new use-case, you either end up duplicating parts of the existing taxonomy (the duplication by necessity problem), or you refactor everything that depends on the existing taxonomy to adapt the taxonomy to the new use case due to the fragile base class problem.

Composition is immune to both.

You think you know Prototypes, but…

If you were taught to build classes or constructor functions and inherit from those, what you were taught was not prototypal inheritance. You were taught how to mimic class inheritance using prototypes.

In JavaScript, class inheritance piggybacks on top of the very rich, flexible prototypal inheritance features built into the language a long time ago, but when you use class inheritance — even the ES6+ `class` inheritance built on top of prototypes, you’re not using the full power & flexibility of prototypal OO. In fact, you’re painting yourself into corners and opting into all of the class inheritance problems.

Using class inheritance in JavaScript is like driving your new Tesla Model S to the dealer and trading it in for a rusted out 1973 Ford Pinto.

Source

Almost all by this great article: https://medium.com/javascript-scene/master-the-javascript-interview-what-s-the-difference-between-class-prototypal-inheritance-e4cd0a7562e9

Referential Transparency / Opacity in JS

Referential transparency is used in many domains, for example: mathematics, logic, linguistics, philosophy and programming. It has quite changed meanings in each of these domains.

Referential transparency in programming relates to programs. By the way of programs are composed of subprograms that are programs themselves. It relates to those subprograms, also. Subprograms can be signified by methods.

Example:

var identifty = (i) => { return i }
  • We have defined a simple function named identity in the above code snippet.
  • This function return whatsoever we’re passing as its input.
  • That is, if we passes 10, it returns back the value 10.
  • As the function is only acts as a mirror and identity.
  • Our function does work only on the incoming argument `i`.
  • There is no global reference inside our function.

At the present conceive this function is used between other function calls like this:

sum(4,5) + identity(1)

By means of our Referential Transparency definition we may change the above statement into this:

sum(4,5) + 1
  • At this moment this process is called a Substitution model.
  • By way of we can directly substitute the result of the function as is with its value.
  • Generally due to the function doesn’t rely on other global variables for its logic.
  • This leads to equivalent code and caching.
  • We may easily run the above function with several threads deprived of even the need of synchronizing.
  • The motive for synchronizing comes from the detail that threads shouldn’t do global data when running equivalent.
  • Functions that follow Referential Transparency depends only on inputs from its argument.
  • Therefore, threads are allowed to run without any locking mechanism.
  • Meanwhile the function returns the same value for the given input.
  • We may, actually cache it. For instance, see there is a function called factorial.
  • Calculates the factorial of the given number.
  • Factorial takes the input as its argument for which the factorial needs to be calculated.
  • We all recognize the factorial of 5 going to be 120.
  • What would be if the user calls the factorial of 5 a second time?
  • We see that the result is to be 120 if the factorial function follows Referential transparency as before.
  • It only be contingent on the input argument.
  • We may cache the values of our factorial function by keeping in mind these characters.
  • Thus if a factorial is called for the second time with the input as `5`, we can return the cached value instead of calculating once again.

`An expression is called referentially transparent if it can be replaced with its corresponding value (and vice-versa) without changing the program’s behavior.[1] This requires that the expression be pure – its value must be the same for the same inputs and its evaluation must have no side effects. An expression that is not referentially transparent is called referentially opaque.`

Examples of both:

var g = 0;

function rt (x) {
  return x + 1
}

function ro (x) {
  g++;
  return x + g;
}

console.log(rt(1));
console.log(rt(1));
console.log(rt(1));

console.log(ro(1));
console.log(ro(1));
console.log(ro(1));
2
2
2
2
3
4

What is: Closure

Closures are important because they control what is and isn’t in scope in a particular function, along with which variables are shared between sibling functions in the same containing scope. Understanding how variables and functions relate to each other is critical to understanding what’s going on in your code, in both functional and object oriented programming styles.

Coding without understanding of Closures is like trying to
speak English without understanding the grammar rules.
You might be able to get your ideas across, but probably a
bit awkaardly.

In JS closures are frequently used for data privacy, in event handlers and callback functions, and in partial applications, currying and other functional programming patterns.

What is it?

Is the combination of a function bundled together (enclosed) with references to its surrounding sate (the **lexical environment**). In other words, a closure gives you access to an outer function’s scope from a inner function. In JavaScript, closures are created every time a function is created, at function creation time.

To use a Closure, define a function inside another function and expose it. To expose a function, return it or pass it to another function.

The inner function will have access to the variables in the outer function scope, even after the outer function has returned.

Using Closures (Examples)

Among other things, closures are commonly used to give objects data privacy. Data privacy is an essential property that helps us **program to an interface, not an implementation**. This is an important concept that helps us build more robust software because implementation details are more likely to change in breaking ways than interface contracts.

In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods. In JavaScript, any exposed method defined within the closure scope is privileged. For example:

const getSecret = (secret) => {
  return {
    get: () => secret
  };
};

test('Closure for object privacy.', assert => {
  const msg = '.get() should have access to the closure.';
  const expected = 1;
  const obj = getSecret(1);

  const actual = obj.get();

  try {
    assert.ok(secret, 'This throws an error.');
  } catch (e) {
    assert.ok(true, `The secret var is only available
      to privileged methods.`);
  }

  assert.equal(actual, expected, msg);
  assert.end();
});

In the example above, the `.get()` method is defined inside the scope of `getSecret()`, which gives it access to any variables from `getSecret()`, and makes it a privileged method. In this case, the parameter, `secret`.

Objects are not the only way to produce data privacy. Closures can also be used to create stateful functions whose return values may be influenced by their internal state, e.g.:

`const secret = msg => () => msg;`

// Secret - creates closures with secret messages.
// https://gist.github.com/ericelliott/f6a87bc41de31562d0f9
// https://jsbin.com/hitusu/edit?html,js,output

// secret(msg: String) => getSecret() => msg: String
const secret = (msg) => () => msg;

test('secret', assert => {
  const msg = 'secret() should return a function that returns the passed secret.';

  const theSecret = 'Closures are easy.';
  const mySecret = secret(theSecret);

  const actual = mySecret();
  const expected = theSecret;

  assert.equal(actual, expected, msg);
  assert.end();
});

In functional programming, closures are frequently used for partial application & currying. This requires some definitions:

Application:

The process of applying a function to its arguments in order to produce a return value.

Partial Application:

The process of applying a function to some of its arguments. The partially applied function gets returned for later use. Partial application fixes (partially applies the function to) one or more arguments inside the returned function, and the returned function takes the remaining parameters as arguments in order to complete the function application.

Partial application takes advantage of closure scope in order to fix parameters. You can write a generic function that will partially apply arguments to the target function. It will have the following signature:

partialApply(targetFunction: Function, ...fixedArgs: Any[]) =>
functionWithFewerParams(...remainingArgs: Any[])

It will take a function that takes any number of arguments, followed by arguments we want to partially apply to the function, and returns a function that will take the remaining arguments

An example will help. Say you have a function that adds two numbers:

const add = (a, b) => a + b;

Now you want a function that adds 10 to any number. We’ll call it `add10()`. The result of `add10(5)` should be `15`. Our `partialApply()` function can make that happen:

const add10 = partialApply(add, 10);
add10(5);

In this example, the argument, `10` becomes a fixed parameter remembered inside the `add10()` closure scope.

Let’s look at a possible `partialApply()` implementation:

// Generic Partial Application Function
// https://jsbin.com/biyupu/edit?html,js,output
// https://gist.github.com/ericelliott/f0a8fd662111ea2f569e

// partialApply(targetFunction: Function, ...fixedArgs: Any[]) =>
//   functionWithFewerParams(...remainingArgs: Any[])
const partialApply = (fn, ...fixedArgs) => {
  return function (...remainingArgs) {
    return fn.apply(this, fixedArgs.concat(remainingArgs));
  };
};


test('add10', assert => {
  const msg = 'partialApply() should partially apply functions'

  const add = (a, b) => a + b;

  const add10 = partialApply(add, 10);


  const actual = add10(5);
  const expected = 15;

  assert.equal(actual, expected, msg);
});

As you can see, it simply returns a function which retains access to the `fixedArgs` arguments that were passed into the `partialApply()` function.

Source:

Heavily based on: https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36

What is: Pure Functions

General Definition

Is a function where:

  • Given the same input, always returns the same output
  • Produces no side effects

Functions as a whole

Is a process of taking some input, called arguments, and producing some output to the called return value.

Main purposes:

  • Mapping: Process output based on given inputs. Maps input values to output values
  • Procedures: A function to perform a sequence of steps. This is style is procedural programming.
  • I/O: In order to communicate with the system: screen, storage, logs, network.

Back to definition

If a function where:

  • Given the same input, always returns the same output
  • Produces no side effects

If I have a function like:

function double(number) {
    return 2 * number;
}

I can say that these are both “the same”

console.log(double(5));
console.log(10);        // They produces the same result

If you want **Referential Transparency** you need to use pure functions.

A dead giveaway that a function is impure is if it makes sense to call it without using its return value. For pure functions, that’s a nope.

Recommendation

Favor pure functions: If it is practical to implement a program requirement using pure functions, you should use them over other options. They are the simplest reusable build blocks of code in a program.

The most important design principle (KISS)

Keep it Simple Stupid or, Keep it Stupid Simple

Pure functions are completely independent of outside state, and as such, they are immune to entire classes of bugs that happen with a shared mutable state.

This independent nature makes them great candidates for parallel processing across many CPUs and distribute clusters.

They are also easier to move around, refactor, and reorganize in the code, making programs more flexible and adaptable to future changes.

Problem with Shared State

In an example: if you make requests from a query text field as the user types. You may have times where the last request “Java” for example comes and occupies the UI response element, before the request for “JavaScript” was even sent.

To fix this, you should build a manager that cancels the previous AJAX request.

Martin Odersky (Creator of Scala) puts it: `non-determinism = parallel processing + mutable state`

You should avoid it.

Program determinism is a LOT desirable in computing. If you think JS is immune because it only use single thread. Remember that AJAX, API I/O event listeners, web workers, iframes and timeouts can introduce indeterminism into your program. Combine that with shared state, you have a recipe for bugs.

Given the same Input, Always Returns the Same Output

Our `double` function will always return 10 for 5 as parameter, it doesn’t matter how many times we call it

But we can’t say the same for `Math.random()` for example.

Math.random();
// 0.8335683328172347

Math.random();
// 0.8910118593581697

Math.random();
//0.3099123827043109

Even tough we didn’t pass any arguments into any of the function calls, they produced different output. This function is not pure.

const time = () => new Date().toLocaleTimeString();

time(); // '8:45:51 AM'

This is also not pure, even thought it repeats its output one time each day.

Now an example of pure function:

const highpass = (cutoff, value) => value >= cutoff;

highpass(5, 5); // => true  Always the same result given the same inputs
highpass(5, 5); // => true
highpass(5, 5); // => true

highpass(5, 123); // true  Many inputs may map to the same ouputs
highpass(5, 6);   // true
highpass(5, 18);  // true
highpass(5, 1);   // false
highpass(5, 3);   // false
highpass(5, 4);   // false

A pure function must not rely on any external mutable state, because it would no longer be deterministic or referentially transparent.

Pure functions Produce No SIDE EFFECTS

A pure function produces no side effects, which means that it can’t alter any external state.

Immutability

JavaScript’s object arguments are references, which means that if a function were to mutate a property on an object or array parameter, that would mutate state that is accessible outside the function. Pure functions must not mutate external state.

Consider this mutating, impure `addToCart()` function:

// impure addToCart mutates existing cart
const addToCart = (cart, item, quantity) => {
  cart.items.push({
    item,
    quantity
  });
  return cart;
};


test('addToCart()', assert => {
  const msg = 'addToCart() should add a new item to the cart.';
  const originalCart =     {
    items: []
  };
  const cart = addToCart(
    originalCart,
    {
      name: "Digital SLR Camera",
      price: '1495'
    },
    1
  );

  const expected = 1; // num items in cart
  const actual = cart.items.length;

  assert.equal(actual, expected, msg);

  assert.deepEqual(originalCart, cart, 'mutates original cart.');
  assert.end();
});

It works by passing a cart and item to add to the cart. The function then returns the same cart, with the item added to it.

The problem is that we’ve just mutated some shared state. Other functions may be relying on that cart object state to be what it was before the function was called and now we have to worry about what impact it will have on the program logic if we change the order. Refactoring the code could result in bugs popping up and unhappy customers.

Consider this version:

// Pure addToCart() returns a new cart
// It does not mutate the original.
const addToCart = (cart, item, quantity) => {
  const newCart = lodash.cloneDeep(cart);

  newCart.items.push({
    item,
    quantity
  });
  return newCart;

};


test('addToCart()', assert => {
  const msg = 'addToCart() should add a new item to the cart.';
  const originalCart = {
    items: []
  };

  // deep-freeze on npm
  // throws an error if original is mutated
  deepFreeze(originalCart);

  const cart = addToCart(
    originalCart,
    {
      name: "Digital SLR Camera",
      price: '1495'
    },
    1
  );


  const expected = 1; // num items in cart
  const actual = cart.items.length;

  assert.equal(actual, expected, msg);

  assert.notDeepEqual(originalCart, cart,
    'should not mutate original cart.');
  assert.end();
});

In this example, we have an array nested in an object, which is why I reached for a deep clone. This is more complex state than you’ll typically be dealing with. For most things, you can break it down into smaller chunks.

For example, Redux lets you compose reducers rather than deal with the entire app state inside each reducer. The result is that you don’t have to create a deep clone of the entire app state every time you want to update just a small part of it. Instead, you can use non-destructive array methods, or `Object.assign()` to update a small part of the app state.

Source

This topic is based on: https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976

New features of ES13

Class Field Declarations

Before ES13 we could not declare class fields outside the constructor:

class Car {
  constructor() {
    this.color = 'blue';
    this.age = 2;
  }
}
const car = new Car();
console.log(car.color); // blue
console.log(car.age); // 2

ES13 removes this limitation:

class Car {
  color = 'blue';
  age = 2;
}
const car = new Car();
console.log(car.color); // blue
console.log(car.age); // 2

Private Methods and Fields

Members were usually prefixed with an _ to indicate it should be private. But could still be accessed from outside.

class Person {
  _firstName = 'Joseph';
  _lastName = 'Stevens';
  get name() {
    return `${this._firstName} ${this._lastName}`;
  }
}

const person = new Person();
console.log(person.name); // Joseph Stevens

// Members intended to be private can still be accessed
// from outside the class
console.log(person._firstName); // Joseph
console.log(person._lastName); // Stevens

// They can also be modified
person._firstName = 'Robert';
person._lastName = 'Becker';
console.log(person.name); // Robert Becker

Now we use # to add private fields to our classes

class Person {
  #firstName = 'Joseph';
  #lastName = 'Stevens';
  get name() {
    return `${this.#firstName} ${this.#lastName}`;
  }
}

const person = new Person();

console.log(person.name);

// SyntaxError: Private field '#firstName' must be
// declared in an enclosing class
console.log(person.#firstName);
console.log(person.#lastName);

await Operator at Top level

Previously we could only use await with async function. We could not use this in the global scope.

  function setTimeoutAsync(timeout) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, timeout);
  });
}

// SyntaxError: await is only valid in async functions
await setTimeoutAsync(3000);

Now it is possible:

function setTimeoutAsync(timeout) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, timeout);
  });
}

// Waits for timeout - no error thrown
await setTimeoutAsync(3000);

Static Class Fields and Static Private Methods

We can now declare static fields and static private methods for a class in ES13. Static methods can access other private/public static members in the class using the this keyword, and instance methods can access them using this.constructor.

class Person {
  static #count = 0;
  static getCount() {
    return this.#count;
  }
  constructor() {
    this.constructor.#incrementCount();
  }
  static #incrementCount() {
    this.#count++;
  }
}

const person1 = new Person();
const person2 = new Person();
console.log(Person.getCount()); // 2

Class static Block

ES13 allows the definition of static blocks that will be executed only once, at the creation of the class. This is similar to static constructors in other languages with support for object-oriented programming, like C# and Java.

A class can have any number of static {} initialization blocks in its class body. They will be executed, along with any interleaved static field initializers, in the order they are declared. We can use the super property in a static block to access properties of the super class.

class Vehicle {
  static defaultColor = 'blue';
}

class Car extends Vehicle {
  static colors = [];
  static {
    this.colors.push(super.defaultColor, 'red');
  }
  static {
    this.colors.push('green');
  }
}

console.log(Car.colors); // [ 'blue', 'red', 'green' ]

Ergonomic Brand Checks for Private Fields

We can use this new feature to check if an object has a particular private field in it, using the in operator.

class Car {
  #color;
  hasColor() {
    return #color in this;
  }
}

const car = new Car();
console.log(car.hasColor()); // true;

The in operator can correctly distinguish private fields with the same names from different classes:

class Car {
  #color;
  hasColor() {
    return #color in this;
  }
}

class House {
  #color;
  hasColor() {
    return #color in this;
  }
}

const car = new Car();
const house = new House();
console.log(car.hasColor()); // true;
console.log(car.hasColor.call(house)); // false
console.log(house.hasColor()); // true
console.log(house.hasColor.call(car)); // false

at() Method for Indexing

We typically use square brackets ([]) in JavaScript to access the Nth element of an array, which is usually a simple process. We just access the N - 1 property of the array.

const arr = ['a', 'b', 'c', 'd'];
console.log(arr[1]); // b

However, we have to use an index of arr.length - N if we want to access the Nth item from the end of the array with square brackets.

const arr = ['a', 'b', 'c', 'd'];

// 1st element from the end
console.log(arr[arr.length - 1]); // d

// 2nd element from the end
console.log(arr[arr.length - 2]); // c

The new at() method lets us do this more concisely and expressively. To access the Nth element from the end of the array, we simply pass a negative value of -N to at().

const arr = ['a', 'b', 'c', 'd'];

// 1st element from the end
console.log(arr.at(-1)); // d

// 2nd element from the end
console.log(arr.at(-2)); // c

Apart from arrays, strings and TypedArray objects also now have at() methods.

const str = 'Coding Beauty';

console.log(str.at(-1)); // y
console.log(str.at(-2)); // t

const typedArray = new Uint8Array([16, 32, 48, 64]);

console.log(typedArray.at(-1)); // 64
console.log(typedArray.at(-2)); // 48

RegExp Match Indices

This new feature allows us to specify that we want the get both the starting and ending indices of the matches of a RegExp object in a given string. Previously, we could only get the starting index of a regex match in a string.

const str = 'sun and moon';
const regex = /and/;
const matchObj = regex.exec(str);

// [ 'and', index: 4, input: 'sun and moon', groups: undefined ]
console.log(matchObj);

We can now specify a d regex flag to get the two indices where the match starts and ends. With the d flag set, the object returned will have an indices property that contains the starting and ending indices.

const str = 'sun and moon';
const regex = /and/d;
const matchObj = regex.exec(str);
/*
[
  'and',
  index: 4,
  input: 'sun and moon',
  groups: undefined,
  indices: [ [ 4, 7 ], groups: undefined ]
]
 */
console.log(matchObj);

Object.hasOwn() Method

In JavaScript, we can use the Object.prototype.hasOwnProperty() method to check if an object has a given property.

class Car {
  color = 'green';
  age = 2;
}
const car = new Car();

console.log(car.hasOwnProperty('age')); // true
console.log(car.hasOwnProperty('name')); // false

But there are certain problems with this approach. For one, the Object.prototype.hasOwnProperty() method is not protected - it can be overridden by defining a custom hasOwnProperty() method for a class, which could have completely different behavior from

Object.prototype.hasOwnProperty().

class Car {
  color = 'green';
  age = 2;
  // This method does not tell us whether an object of
  // this class has a given property.
  hasOwnProperty() {
    return false;
  }
}

const car = new Car();

console.log(car.hasOwnProperty('age')); // false
console.log(car.hasOwnProperty('name')); // false

Another issue is that for objects created with a null prototype (using Object.create(null)), trying to call this method on them will cause an error.

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;

// TypeError: obj.hasOwnProperty is not a function
console.log(obj.hasOwnProperty('color'));

One way to solve these issues is to use to call the call() method on the Object.prototype.hasOwnProperty Function property, like this:

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;

console.log(Object.prototype.hasOwnProperty.call(obj, 'color')); // true
console.log(Object.prototype.hasOwnProperty.call(obj, 'name')); // false

This isn’t very convenient. We can write a reusable function to avoid repeating ourselves:

function objHasOwnProp(obj, propertyKey) {
  return Object.prototype.hasOwnProperty.call(obj, propertyKey);
}

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;

console.log(objHasOwnProp(obj, 'color')); // true
console.log(objHasOwnProp(obj, 'name')); // false

No need for that though, as we can use the new built-in Object.hasOwn() method. Like our reusable function, it takes an object and property as arguments and returns true if the specified property is a direct property of the object. Otherwise, it returns false.

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;

console.log(Object.hasOwn(obj, 'color')); // true
console.log(Object.hasOwn(obj, 'name')); // false

Error Cause

Error objects now have a cause property for specifying the original error that caused the error about to be thrown. This helps to add additional contextual information to the error and assist the diagnosis of unexpected behavior. We can specify the cause of an error by setting a cause property on an object passed as the second argument to the Error() constructor.

function userAction() {
  try {
    apiCallThatCanThrow();
  } catch (err) {
    throw new Error('New error message', { cause: err });
  }
}
try {
  userAction();
} catch (err) {
  console.log(err);
  console.log(`Cause by: ${err.cause}`);
}

Array Find from Last

In JavaScript, we can already use the Array find() method to find an element in an array that passes a specified test condition. Similarly, we can use findIndex() to find the index of such an element. While find() and findIndex() both start searching from the first element of the array, there are instances where it would be preferable to start the search from the last element instead.

There are scenarios where we know that finding from the last element might achieve better performance. For example, here we’re trying to get the item in the array with the value prop equal to y. With find() and findIndex():

const letters = [
  { value: 'v' },
  { value: 'w' },
  { value: 'x' },
  { value: 'y' },
  { value: 'z' },
];

const found = letters.find((item) => item.value === 'y');
const foundIndex = letters.findIndex((item) => item.value === 'y');

console.log(found); // { value: 'y' }
console.log(foundIndex); // 3

This works, but as the target object is closer to the tail of the array, we might be able to make this program run faster if we use the findLast() and findLastIndex() methods to search the array from the end.

const letters = [
  { value: 'v' },
  { value: 'w' },
  { value: 'x' },
  { value: 'y' },
  { value: 'z' },
];

const found = letters.findLast((item) => item.value === 'y');
const foundIndex = letters.findLastIndex((item) => item.value === 'y');

console.log(found); // { value: 'y' }
console.log(foundIndex); // 3

Another use case might require that we specifically search the array from the end to get the correct item. For example, if we want to find the last even number in a list of numbers, find() and findIndex() would produce a wrong result:

const nums = [7, 14, 3, 8, 10, 9];
// gives 14, instead of 10

const lastEven = nums.find((value) => value % 2 === 0);
// gives 1, instead of 4

const lastEvenIndex = nums.findIndex((value) => value % 2 === 0);
console.log(lastEven); // 14
console.log(lastEvenIndex); // 1

We could call the reverse() method on the array to reverse the order of the elements before calling find() and findIndex(). But this approach would cause unnecessary mutation of the array, as reverse() reverses the elements of an array in place. The only way to avoid this mutation would be to make a new copy of the entire array, which could cause performance problems for large arrays.

Also, findIndex() would still not work on the reversed array, as reversing the elements would also mean changing the indexes they had in the original array. To get the original index, we would need to perform an additional calculation, which means writing more code.

const nums = [7, 14, 3, 8, 10, 9];

// Copying the entire array with the spread syntax before
// calling reverse()
const reversed = [...nums].reverse();

// correctly gives 10

const lastEven = reversed.find((value) => value % 2 === 0);
// gives 1, instead of 4

const reversedIndex = reversed.findIndex((value) => value % 2 === 0);
// Need to re-calculate to get original index

const lastEvenIndex = reversed.length - 1 - reversedIndex;

console.log(lastEven); // 10
console.log(reversedIndex); // 1
console.log(lastEvenIndex); // 4

It’s in cases like where the findLast() and findLastIndex() methods come in handy.

const nums = [7, 14, 3, 8, 10, 9];

const lastEven = nums.findLast((num) => num % 2 === 0);

const lastEvenIndex = nums.findLastIndex((num) => num % 2 === 0);

console.log(lastEven); // 10
console.log(lastEvenIndex); // 4

Source

This topic came from: https://medium.com/javascript-in-plain-english/es13-javascript-features-eed7ed2f1497

javascript-notes's People

Contributors

lionyxml avatar

Stargazers

Roman avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.