101 Javascript Tricks

👋 Hello and welcome to this site! My goal is to collect and bring 101 interesting things from the Javascript world. The site is not finished yet since I continuously work on adding the content. Despite this, the [https://github.com/omachala/101-javascript-tricks](Pull Requests) are more than welcome! 🙏

Enjoy the reading!

I consider myself as Javascript:

Operators

this is operators section description

1.Equality operators

beginner

The result of evaluating an equality operator is always of type Boolean based on the comparison result.

"hello" == "hello"; // true
true == false; // false
true != false; // true
1 == true; // true
0 == false; // true

When you look at the last two examples you can notice that the results are true even the operands are not exactly the same. That's because the javascript engine tries to convert operands to the same type before comparing.

Because of that the recommendation is to use exclusively the Identity === and Nonidentity !== operators.

"hello" === "hello"; // true
true === false; // false
true !== false; // true
1 === true; // false
0 === false; // false

Let's also have a look into another interesting scenario with objects:

const fruit = { name: "orange " };
const fruit2 = { name: "orange" };
fruit === fruit; // true
fruit === fruit2; // false

The fruit === fruit2 returns false because both operands (even look the same) point to the different object (different address in the memory).

I use itand I think it's

2.Assignment operators

beginner

An assignment operators assigns a value to its left operand based on the value of its right operand. See addition assignment example:

let x = 2;
x += 3; // is equivalent to: x = x + 3;
x; // 5

More examples:

let a = b = c = d = 12
a *= 2; // 24
b -= 4; // 8
c /= 3; // 4
d %= 5; // 2

There are also shift bitwise and logical assignments you can find in the documentation.

I use itand I think it's

3.Ternary operator

beginner

The ternary operator takes three operands and is basically a shortcut for the if statement.

let result = 1 === 1 ? "equal" : "not equal";
result; // 'equal'

// Is the same as:

if (1 === 1) {
  result = "equal";
} else {
  result = "not equal";
}
result; // equal

The ternary operator can be chained which is equivalent to if … else if … else statement chain:

const x = 3;
const y = x == 1 ? 1 : x == 2 ? 2 : x == 3 ? 3 : "more than 3";
y; // 3
I use itand I think it's

4.Delete operator

beginner

The delete operator deletes an object's property.

If the operation is possible then true is returned and object is modified inplace. The false is returned if operation has failed.

const obj = { a: 1, b: 2 };
delete obj.a; // true
obj; // { b: 2 }

It's also technically possible to use it for arrays by pointing the index (since arrays are just objects) but it keeps the original array length and it's generally a bad practice - use array methods instead.

// avoid this usage!
const arr = [1, 2, 3];
delete arr[1]; // true
arr; // [ 1, <1 empty item>, 3 ]
arr.length; // 3
I use itand I think it's

5.In operator

intermediate

The in operator returns true/false if the specified property exists in the given object:

"a" in { a: 1 }; // true
"b" in { a: 1 }; // false

For the arrays the array index is considered as a property:

"b" in ["a", "b"]; // false
1 in ["a", "b"]; // true
I use itand I think it's

6.Spread operator

beginner

Spread operator is extremely common and useful syntax allows you inplace expand iterables (array, object, string, ...). The most common usage is "concatenating" arrays and objects:

const obj = { a: 1, b: 2 };
{ ...obj, c: 3 }; // { a: 1, b: 2, c: 3 }
{ ...obj, a: 3 }; // { a: 3, b: 2 }
{ a:3, ...obj }; // { a: 1, b: 2 }

const arr = [ 1, 2 ];
[ ...arr, 5, 6 ]; // [ 1, 2, 5, 6 ]

Please note: Spread operator may NOT be appropriate for object copying as it's doing shallow copy only. This means it duplicates only the top-level properties, but the nested objects still keep their original references.

Rest syntax (parameters) which is the opposite of spread syntax - collects multiple values (function arguments) into array:

function favouriteFruits(...fruits) {
  console.log(fruits.join(", "));
}

favouriteFruits("banana", "apple", "mango"); // 'banana, apple, mango'
I use itand I think it's

7.Exponentiation operator

beginner

The exponentiation operator (**) is a shortcut of the Math.pow function (except it also accepts BigInts as operands) and returns the result of raising the first operand to the power of the second operand

2 ** 3; // 8 (2 * 2 * 2)
4 ** 5; // 1024
2 ** (3 ** 2); // 512

Similar is exponentiation assignment **= which raises the value of a variable to the power of the right operand.

let a = 2;
a **= 4; // 16
I use itand I think it's

8.Comma operator

expert

The comma , operator enables you to create compound expression of multiple operands where the value of the last one is returned.

let x = 1;
y = (x++, 100);
x; // 2
y; // 100

This can be handy for reduce array method where you want to do a simple operation and return accumulator.

["a", "b", "c"].reduce((acc, char) => ((acc[char] = true), acc), {}); // { a: true, b: true, c: true }

You can supply multiple parameters in a for loop:

for (let x = 0, y = 100; x <= 100; y++, y--) {
  console.log(x, y);
}

Or define multiple variables:

let a, b, c;
I use itand I think it's

9.Void operator

expert

The void is unary operator evaluates the given expression and then returns undefined.

You can create an immediately-invoked function and force it to be forgotten (the function keyword to be treated as an expression instead of a declaration).

void function myFunction() {
  console.log('myFunction has been executed!');
}(); // 'myFunction has been executed!'

myFunction; // ReferenceError: myFunction is not defined
myFunction(); // ReferenceError: myFunction is not defined
I use itand I think it's

10.Optional Chaining

beginner

The optional chaining (?.) operator allows you to read values deeply nested within a chain of connected objects even when any of nested object can be null or undefined.

Consider following object:

const person = {
  name: "Alice",
};
console.log(person.address.street.number); // TypeError: Cannot read property 'street' of undefined

To avoid the error you normally need to use some conditional expression:

if (person.address && person.address.street && person.address.street.number) {
  console.log(person.address.street.number);
}
// or
person.address && person.address.street && person.address.street;

Using the optional chaining you can simply do:

person.address?.street?.number; // undefined

Using optional chaining with method calls automatically returns undefined instead of throwing an exception:

person.getAge(); // TypeError: person.getAge is not a function
person.getAge?.(); // undefined
I use itand I think it's

11.Nullish coalescing

intermediate

The Nullish coalescing operator returns the right-hand side of the operand only if the left-hand operand is null or undefined. This is useful when you work with numbers and do not want to consider zero 0 as an invalid value or for strings where empty string "" can still be considered as a valid value.

The widely used logical OR || operator can't be sometimes properly used for numbers and strings:

0 || 'hello' // 'hello'
'' || 'hello' // 'hello'

0 ?? 'hello' // 0
'' ?? 'hello' // ''
I use itand I think it's

12.Logical nullish assignment

expert

The logical nullish assignment operator ?== only assigns value to an object property if it does not exists (is undefined) or has null value (=nullish).

const person = { name: "Alice" };

person.name ??= "Bob";
person; // { name: 'Alice' }

person.age ??= "30";
person; // { name: 'Alice', age: '30' }
I use itand I think it's

13.typeof vs instanceof

intermediate

Both typeof and instanceof identify the type of a value but the difference is that:

  • typeof returns alway string like "number", "string", "boolean" or "undefined" indicating the type of the operand

  • instanceof stands for constructors (functions, classes) and returns true if the value is a child of the right-hand-side callable object

class Car {}
class Animal {}
class Fish extends Animal {}
const nemo = new Fish();

nemo instanceof Object; // true
nemo instanceof Animal; // true
nemo instanceof Fish; // true
nemo instanceof Car; // false
nemo instanceof nemo; // TypeError: Right-hand side of 'instanceof' is not callable

typeof nemo; // 'object'
typeof Animal; // 'function'
typeof 12; // 'number'
typeof something; // 'undefined'
I use itand I think it's

14.Bitwise operator

expert

const bob = { name: "Bob", permission: 0 };

const permissions = ["read", "write", "execute", "delete"];

const getPermissionValue = (permArray) => {
  return permArray.reduce((acc, value) => {
    let index = permissions.indexOf(value);
    return index === -1 ? acc : acc | (1 << index);
  }, 0);
};

bob.permission = getPermissionValue(["read", "execute", "delete"]); // 3
bob; // { name: 'Bob', permission: 3 }
bob.permission.toString(2); // 1101 it means the permissions array from right to left

const verifyOperation = (permission, permissions) => {
  return permission === (permission | getPermissionValue(permissions));
};

verifyOperation(bob.permission, ["read"]); // true
verifyOperation(bob.permission, ["write"]); // false
verifyOperation(bob.permission, ["execute"]); // true
verifyOperation(bob.permission, ["execute", "read"]); // true
verifyOperation(bob.permission, ["read", "write"]); // false
I use itand I think it's

15.new.target

expert

The new.target pseudo function property (only exists within functions) stands for detecting whether the function has been invoked using the new operator.

function Animal(name) {
  if (new.target) {
    throw new TypeError("Animal is not a constructor.");
  }
  console.log(name);
}

new Animal("giraphe"); // TypeError: Animal is not a constructor.
Animal("giraphe"); // 'giraphe'

This is useful in cases when you don't want to allow invoking your function using the new keyword as it might not be a useful or legal usage. This can of course be used vice versa if(!new.target) and require invoking your function only by using the new keyword.

I use itand I think it's

Built-in Objects

16.Boolean

intermediate

The Boolean is an object wrapper for a boolean value. It evaluates its argument as true or false. It can be used using the new keyword or without.

Boolean(true); // true
Boolean(0); // false
Boolean("hello"); // true
Boolean(); // false

const x = new Boolean(1);
x.valueOf(); // true
x.toString(); // 'true'

You can for example use the Boolean as a filter function:

const data = ["hello", 0, undefined, "world", ""];
data.filter(Boolean); // [ 'hello', 'world' ]
I use itand I think it's

17.Infinity

expert

The Infinity is simple global object representing an infinity as a numeric value. It can be used as -Infinity for "the lowest" possible (lower then any finite) and Infinity for "the highest" possible (higher then any finite) number.

A good usecase is usage of Infinity or -Infinity as starting points when number of array needs to be processed and compared:

// the smallest
[8, 2, 1].reduce((smallest, num) => Math.min(smallest, num), Infinity); // 1
// the highest
[8, 2, 1].reduce((highest, num) => Math.max(highest, num), -Infinity); // 8

Note: The previous example is a simple demonstration of how Infinity works. If you really want to find the highest/smallest number in array use more performant solution:

Math.min(...[8, 2, 1]); // 1
Math.max(...[8, 2, 1]); // 8
I use itand I think it's

18.Number object

expert

The Number object offers some numerical constants properties, such as max value, not-a-number, and infinity.

Number.MAX_VALUE; // The largest possible number (±1.7976931348623157e+308)
Number.MIN_VALUE; // The smallest possible number (±5e-324)
Number.NaN; // "Not a Number" value
Number.NEGATIVE_INFINITY; // Representation of negative infinite value (-Infinity)
Number.POSITIVE_INFINITY; // Representation positive infinite value (Infinity)
Number.EPSILON; // Difference between 1 and the smallest value greater than 1 that can be represented as a Number (2.220446049250313e-16)
Number.MIN_SAFE_INTEGER; // Minimum safe integer (−9007199254740991)
Number.MAX_SAFE_INTEGER; // Maximum safe integer (+9007199254740991)
I use itand I think it's

19.Set

intermediate

The Set object stands for storing any unique primitive values or object references. So it's being very commonly used for collection or in-place filtering of unique values.

const cats = new Set();
cats.add("Daisy").add("Bella").add("Lilly").add("Daisy");
cats.size; // 3 (because keeps unique only)
cats.delete("Bella"); // true
cats.size; // 2
Array.from(cats); // [ 'Daisy', 'Lilly' ]

Getting unique values from array:

const input = [1, 2, 1, 3, 2, 1, 3, 2];
const unique = [...new Set(input)];
unique; // [ 1, 2, 3 ]

Iteration over Set

for (let cat of cats) {
  console.log(cat);
}

cats.forEach((cat) => {
  console.log(cat);
});

// for both the output is identical:
// 'Daisy'
// 'Lilly'
I use itand I think it's

20.Map

intermediate

The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.

The functionality of the Map object is similar to standard object - both let you set keys to values, retrieve values, delete keys and detect existing key. However, there are differences that make Map preferable in certain cases.

Advantages Map over standard object:

  • easy getting the number of items (the .size property)

  • keys can be any value (including functions, objects, or any primitive)

  • keeps keys, and values in the order of entry insertion

  • is an iterable, so it can be directly iterated

  • generally better performance

const cats = new Map();
cats.set("bella", { color: "ginger" }).set("daisy", { color: "black" });
cats.size; // 2
cats.has("bella"); // true
cats.get("bella"); // { color: 'ginger' }

Map to array

[...cats]; // [ [ 'bella', { color: 'ginger' } ], [ 'daisy', { color: 'black' } ] ]

// or mapping to custom format:

Array.from(cats, ([name, data]) => ({ name, data }));
// [
//   { name: 'bella', data: { color: 'ginger' } },
//   { name: 'daisy', data: { color: 'black' } }
// ]

Map to Object

Object.fromEntries(cats); // { bella: { color: 'ginger' }, daisy: { color: 'black' } }

Iteration over Map

for (let [key, value] of cats) {
  console.log(key, value);
}

cats.forEach((value, key) => {
  console.log(key, value);
});

// for both the output is identical:
// { color: 'ginger' } 'bella'
// { color: 'black' } 'daisy'
I use itand I think it's

21.Function .call() and .apply()

expert

In javascript, the this represents the context of the function invocation. In the other words, the value of this depends on how the function has been invoked. One of the ways of function invocation is "indirect invocation" using built-in Function methods such as apply() and call() which allows you to pass your own context (value for this).

Both method invokes a function with a given this value (first argument), and arguments provided as an array if you use apply() or individually if you use call(). Both methods also executes the function immediately.

function myFunction(a, b) {
  console.log(a, b, this.x);
}
myFunction(100, 200); // 100 200 undefined
myFunction.apply({ x: 5 }, [100, 200]); // 100 200 5
myFunction.call({ x: 5 }, 100, 200); // 100 200 5

You can find thousands of articles explaining the difference between call() and apply() but it's rarely explained why is this useful and how is this possible?

Well, Javascript treats functions as first-class citizens this allows you to store function into a variable, pass a function as an argument into another function or even return a function from function (higher-order function). An because of this nature sometimes you may need a mechanism to execute a free-standing function without the context of the object where the function is attached to.

I use itand I think it's

22.globalThis

expert

The globalThis property provides a standard way of accessing the global this value (and hence the global object itself) across different environments. The reason for creating this property was that on the web there is window, self, or frames. For Web Workers only self is supported and NodeJS uses its own global.

console.log(globalThis); // Window [global] { ... }
I use itand I think it's

23.Symbol

expert

The Symbol is a function which returns symbol which is primitive data type (like string, number, null etc.)

typeof Symbol(); // 'symbol'

The symbol can be used as a key in object and simulate private object fields:

const person = {};
const name = Symbol();
person[name] = 'Jim';
person.age = 40;
Object.keys(person); // [ 'age' ]
JSON.stringify(person); // '{"age":40}'

Even thought you can still access the symbol key by Reflect.ownKeys(person) and for the private properties you can rather use the private class fields by the hash # prefix.

So why the symbol is useful? Imagine situation you've create an object and you don't want to allow anyone to override some properties

const person = {};
let name = Symbol('name');
person[name] = 'Jim';

// creating new symbol with the same name
name2 = Symbol('name');
person[name2] = 'James';

person[name2]; // 'James'
person[name]; // 'Jim'

Even I created a new symbol with the same name I wasn't been able to override the existing object in field that's bause the Symbol function always returns unique value.

I use itand I think it's

Arrays

24.Array Length

beginner

The Array.length is a very commonly used property to get the actual length of the given array but I want to show you 2 useful concepts:

Shortening an array by changing the length property value:

const numbers = [1, 2, 3, 4];
numbers.length = 2;
numbers; // [ 1, 2 ]

Create empty array of fixed length by defining an empty array and changing the length property value:

const numbers = [];
numbers.length = 3;
numbers; // [ <3 empty items> ]

By the way another way of creating a new array with fixed length is:

const numbers = new Array(3);
numbers; // [ <3 empty items> ]
I use itand I think it's

25.Remove duplicates

beginner

For removing duplicates from array is very commonly used the Set. In first step we need to create new Set from the source array and then transer the Set object back to array. See examples:

const number = [1, 5, 3, 1, 8, 2, 5, 8];

// example 1
const uniqueNumbers = Array.from(new Set(number));
uniqueNumbers; // [ 1, 5, 3, 8, 2 ]

// example 2
const uniqueNumbers2 = [...new Set(number)];
uniqueNumbers2; // [ 1, 5, 3, 8, 2 ]

It's important to say this solution has complexity O(1) (constant) which means that any solution using iterations is not acceptable.

I use itand I think it's

26.Array Fill

intermediate

If you need to create an array with some initial data, the correct way is use the Array.fill method.

const greetings = Array(3).fill("hi");
greetings; // [ 'hi', 'hi', 'hi' ]

The .fill() method has also start and end arguments which allows you fill just specified part of the source array:

const greetings = Array(3).fill("hi").fill("hello", 1, 2);
greetings; // [ 'hi', 'hello', 'hi' ]
I use itand I think it's

27.Array to Object

beginner

Since arrays are just a special type of object in Javascript, we can use Object.assign or just destruct an array into an object to get an object from that array.

const fruits = ["banana", "apple", "orange", "lemon"];

// example 1
const fruitsObject = Object.assign({}, fruits);
fruitsObject; // { '0': 'banana', '1': 'apple', '2': 'orange', '3': 'lemon' }

// example 2
const fruitsObject2 = { ...fruits };
fruitsObject2; // { '0': 'banana', '1': 'apple', '2': 'orange', '3': 'lemon' }
I use itand I think it's

28.Merge Arrays

intermediate

To merge two (or multiple) arrays together you can use the .push() method which accepts unlimited number of arguments, the .concat() method or just simply destruct the source arrays into a target array. Each method may be appropriate in a different case based on whether the source array can be mutated or not.

const fruits = ['orange', 'apple'];
const vegetables = ['potato', 'carrot'];

// example 1
fruits.push(...vegetables);
fruits; // [ 'orange', 'apple', 'potato', 'carrot' ]

// example 2
fruits.concat(vegetables) // [ 'orange', 'apple', 'potato', 'carrot' ]

// example 3
[...fruits, ...vegetables]; // [ 'orange', 'apple', 'potato', 'carrot' ]
I use itand I think it's

29.Array Intersection

intermediate

There is no built-in method or shorthand to get an arrays intersection so we have to do it "manually" by iteration using .filter() and .includes() methods:

const fruits1 = ["orange", "apple", "peach"];
const fruits2 = ["apple", "banana", "orange"];

const commonFruits = fruits1.filter((fruit) => fruits2.includes(fruit));
commonFruits; // [ 'orange', 'apple' ]
I use itand I think it's

Objects

Object is javascript is a data structure for encapsulate state and behaviour (properties and method). JavaScript is an object-based language which efectively means everything (even Fucntion) is an object.

JavaScript is template based not class based. This means we don't need to create class and create object as an instance of that class, we can create object directly.

30.Object.assign()

beginner

The Object.assign() method allows you to assign properties of one object to another. This can be used for object merging.

const x = { a: 1, b: 2 };
const y = { c: 3, d: 4 };
Object.assign(x, y);
x; // { a: 1, b: 2, c: 3, d: 4 }
y; // { c: 3, d: 4 }

Merging multiple objects:

const merged = Object.assign({}, { a: 1 }, { b: 2 });
merged; // { a: 1, b: 2 }

Please note: Object.assign() is not suitable for deep cloning because if some property is an object then it only copies the reference value (still pointing the same object).

I use itand I think it's

31.Object.create()

intermediate

The Object.create() method allows you crate new object based on existing one. The source object is used as a prototype of for the new object. Let's explore the following behaviour:

const source = { a: 1, b: 2 };
const target = Object.create(source);

source; // { a: 1, b: 2 }
target; // { __proto__: { a: 1, b: 2 } }

source.a = 10;
target.a; // 10

source.a = 100;
target; // { a: 100, __proto__: { a: 100, b: 2 } }
source.a; // 10
I use itand I think it's

32.Object.entries()

beginner

The Object.entries returns a given object the object as array of key-value pairs array.

const x = { a: 1, b: 2 };
Object.entries(x); // [ [ 'a', 1 ], [ 'b', 2 ] ]

Object.entries(x).forEach(([key, value]) =>
  console.log(`key: ${key}, value: ${value}`)
);
// 'key: a, value: 1'
// 'key: b, value: 2'
I use itand I think it's

33.Object.defineProperty()

expert

The Object.defineProperty() is a static method for creating or updating an object property in more precise way than standard equal assignment (a.x = y). The method modifies the object in-place.

const source = { a: 1, b: 2 };
Object.defineProperty(source, "c", { value: 3 });
source; // { a: 1, b: 2 }
source.c; // 3

Strange right? Why the source is now { a: 1, b: 2 } even we've set the c property and obviously direct reading source.c returns the correct value?

The key is the 3rd argument which is a descriptor and can be used to define whether the property can be enumerable, configurable, or writable and also the value itself is read using the getter/setter accessors get and set.

Let's try to continue with the previous example and provide some additional configuration:

Object.defineProperty(source, "d", { value: 4, enumerable: true });
source; // { a: 1, b: 2, d: 4 }
source.d; // 4

Object.defineProperty(source, "e", { value: 5, writable: false });
source.e = 50;
source.e; // 5

Object.defineProperty(source, "f", { value: 6, configurable: false });
Object.defineProperty(source, "f", { value: 60 }); // TypeError: Cannot redefine property: f

There is also Object.defineProperties() static method which is very similar allowing you to define multiple (more than one) properties by single call.

I use itand I think it's

Functions

34.Base64

intermediate

Base64 is a group of encoding schemed to allow represent binary data in an ASCII string format (character set very widely supported by any computer system) by translating the data into a radix-64 representation. This is very useful everywhere you need to transfer the data as text without loss or modification.

In JavaScript there are two functions respectively for decoding and encoding base64 strings:

  1. btoa() creates a base-64 encoded ASCII string from a "string" of binary data

  2. atob() decodes a base64 encoded string

Encode object to base64 string:

const myObject = { a: 1, b: 2 };
// serialize object to string
const json = JSON.stringify(myObject)
// make base64 representation
btoa(json); // 'eyJhIjoxLCJiIjoyfQ=='

Decode base64 string to object:

const json = atob('eyJhIjoxLCJiIjoyfQ=='); // '{"a":1,"b":2}'
const myObj = JSON.parse(json);
myObj; // { a: 1, b: 2 }
I use itand I think it's

Language References

35.Stric mode

expert

Strict mode has been introduced in ECMAScript 5 and allows you to place a program, or a function, in a “strict” operating context. It was also designed in the hope that developers who limit themselves to strict mode would make fewer mistakes leading to bugs.

To invoke strict mode for an entire script, put the exact statement "use strict"; before any other statements. The very beginning of the file or function body.

Example:

myVar = "hello world"; // This will not cause an error.

function myFunction() {
  "use strict";
  myVar = "hello world"; // This will cause an error (myVar is not defined).
}

myFunction();

The NodeJS uses CommonJS modularization by default so you don't need to use strict mode in any of your files.

Since the introduction of ECMAScript 2015, you don’t have to include the 'use strict'; statement when writing JavaScript modules to enable strict mode.

I use itand I think it's

Design Patterns

In this section, I want to focus on the most common patterns in Javascript and try to describe and show usage in the same way as the previous examples - meaning just an introduction describing the purpose and example of code. This might not cover all edge cases of each pattern but there already has been written many articles which goes to depth and you can use for reference. The purpose of this section is a quick introduction and a summary of those patterns.

36.Factory Function

beginner

The factory function pattern is similar to constructors, but instead of using new keywork to instantiate an object, factory functions simply creates and return a new object based on the given properties.

Let's imagine you need to have a re-usable way of creation a specific object - for example object which holds information about a user:

const userFactory = ({ name, dateOfBirth, active = true }) => ({
  name: name ?? "Secret name",
  age: Math.floor((new Date() - dateOfBirth) / (1000 * 60 * 60 * 24 * 365.25)),
  active: Boolean(active),
});

This factory function now encapsulates a logic of creating the user object which allows us to easily create multiple users like:

const alex = userFactory({
  name: 'Alex',
  dateOfBirth: new Date('1985-04-15'),
});

const natalie = userFactory({
  name: 'Natalie',
  dateOfBirth: new Date('1993-04-15'),
  active: false,
});

alex; // { name: 'Alex', age: 35, active: true }
natalie; // { name: 'Natalie', age: 27, active: false }

That's it, a pretty simple and very common pattern.

I use itand I think it's

37.Singleton

intermediate

The Singleton pattern restricts the class instantiation to one instance only. This is useful when exactly one object (of a given type) can be created and coordinate actions across the system.

Since Javascript supports object creation by object literal syntax {} this also is the easiest way of singleton creation.

const singleton = {
  property1: "a",
  property2: "b",
  method1: () => 1 + 1,
  method2: () => 2 + 2,
};

But when we really need to have a class that allows only one instance, then the solution can look like the example below. Once the object is being instantiated for first time it creates and holds new instance instance and in case of a second instantiation attempt, it just returns the existing instance.

class Singleton {
  constructor() {
    if (!Singleton.instance) {
      Singleton.instance = this;
    }
    return Singleton.instance;
  }
}

const instance = new Singleton();
const instance2 = new Singleton();

instance === instance2; // true

Sometimes might be useful to also prevent any changes in the instance properties or values later on in your code. For this purpose you can use the Object.freeze() method.

Object.freeze(instance);
I use itand I think it's

38.Observer

expert

Imagine a situation you need to distribute events across the entire system and also deliver them right in the moment when they arise. For example, once the user is successfully logged in you might need multiple frontend components to get this information for a purpose to change their state and re-render the view. That's exactly what Observer pattern is designed for.

In other words Observer pattern is used when there is one-to-many relationship between objects such as if one object is modified (called Subject), its depenedent objects (Observers) are to be notified automatically.

The simple implementation can look like:

class Subject {
  #listeners = new Set();

  subscribe(callback) {
    this.#listeners.add(callback);
    return { unsubscribe: () => this.#listeners.delete(callback) };
  }

  next(data) {
    this.#listeners.forEach((callback) => callback(data));
  }
}

Now we can create one Subject and multiple Observers who will observe the changes. Each observer has also a way to .unsubscribe() if they don't want to receive new events anymore (for example frontend component is about to be dismounted).

const userLoginSubject = new Subject();

const subscriber1 = userLoginSubject.subscribe((data) =>
  console.log(`subscriber1 received: `, data)
);

const subscriber2 = userLoginSubject.subscribe((data) =>
  console.log("subscriber2 received: ", data)
);

userLoginSubject.next("event 1");
// subscriber1 received: event 1
// subscriber2 received: event 1

subscriber1.unsubscribe();
userLoginSubject.next("event 2");
// subscriber2 received: event 2
I use itand I think it's

39.Builder

beginner

The Builder is a really handy design pattern in situations you need a structure which "collects" information and based on collected data it builds the desired output. It's useful when the final output creation process is complex, the data comes from various resources and we need an intuitive input interface.

class CarBuilder {
  #color = "white";
  #wheels = ["no-wheels"];
  #extras = {};

  addWheel(wheel) {
    this.#wheels.push(wheel);
    return this;
  }

  setColor(color) {
    this.#color = color;
    return this;
  }

  addExtra(name, value) {
    this.#extras[name] = value;
    return this;
  }

  toString() {
    const extras = Object.entries(this.#extras)
      .map((entry) => entry.reverse().join(" "))
      .join(" and ");
    const wheels = this.#wheels.join(" + ");
    return `${this.#color} car with ${wheels} wheels and also ${extras}`;
  }
}

Once we create an instance of the CarBuilder we can simply create a new car using straight forward interface (public methods) and without knowledge of how the final output is being created:

const car = new CarBuilder();

car
  .addWheel("front-left")
  .addWheel("front-right")
  .addWheel("rear-left")
  .addWheel("rear-right")
  .setColor("red")
  .addExtra("seats", "leather")
  .addExtra("speaker", "1000-watt");

String(car);
// 'red car with front-left + front-right + rear-left + rear-right wheels and also leather seats and 1000-watt speaker'
I use itand I think it's

40.Constructor pattern

intermediate

Javascript does not support the standard concept of classes known from other programming languages, classes are in fact just a "special functions" and javascript supports a special constructor functions.

When you invoke a function using the keyword new the javascript will create a new object where the this variable points to this new object and also makes the object prototype property (every function object automatically has a prototype property) visible and accessible to "outside world".

Example of constructor:

function Person({ name, dateOfBirth, active = true }) {
  this.name = name ?? "Secret name";
  this.age = Math.floor(
    (new Date() - dateOfBirth) / (1000 * 60 * 60 * 24 * 365.25)
  );
  this.active = Boolean(active);
  this.city = "London";
}

Now let's create two instances using the new keyword:

const alex = new Person({
  name: "Alex",
  dateOfBirth: new Date("1985-04-15"),
});

const natalie = new Person({
  name: "Natalie",
  dateOfBirth: new Date("1993-04-15"),
  active: false,
});

alex;
// Person {
//   name: 'Alex',
//   age: 35,
//   active: true,
//   city: 'London',
//   __proto__: Person { constructor: ƒ Person() }
// }

natalie;
// Person {
//   name: 'Natalie',
//   age: 27,
//   active: false,
//   city: 'London',
//   __proto__: Person { constructor: ƒ Person() }
// }

Have you noticed the __proto__? Its because Javascript creates a prototype-based instances, so it allows us to get the information what type of instances the persons are:

alex instanceof Person; // true
natalie instanceof Person; // true

Now let's try to create another function using the class keyword (which has been introduced in ES2015 as just a syntactical sugar) and extend our already existing Person:

class Employee extends Person {}

const jack = new Employee({ name: "Jack" });

jack;
// Employee {
//   name: 'jack',
//   age: NaN,
//   active: true,
//   city: 'London',
//   __proto__: Employee { constructor: ƒ Employee() }
// }

observe what instances does it match:

jack instanceof Employee; // true
jack instanceof Person; // true

And now the most important part is that all of the instances have an access to the original Person:

alex.city; // 'London'
natalie.city; // 'London'
jack.city; // 'London'
I use itand I think it's

Statements

41.Label statement

expert

The label statement can be used with break or continue statements. It gives you a way to identify the block of code which can be referred to later on.

const sizes = ["S", "M", "L", "X"];
const colors = ["red", "blue", "green"];

sizesLoop: for (size of sizes) {
  colorsLoop: for (color of colors) {
    console.log(size, color);
    if (size === "M" && color === "blue") {
      continue sizesLoop; // skip the rest of colors and continue with next size value
    }
    if (size === "L" && color === "red") {
      break sizesLoop; // stop the outer sizes loop
    }
  }
}
// 'S' 'red'
// 'S' 'blue'
// 'S' 'green'
// 'M' 'red'
// 'M' 'blue'
// 'L' 'red'
I use itand I think it's

42.Debugger statement

The debugger statement invokes debugging functionality if any available. This practically means placing a breakpoint in your code (the code interpret will stop execution on the required place and enable inspecting the state of the program).

function myFunction() {
  debugger;
  // it'll allow you to step though
  // these lines of code
  // and inspect the state of program (variables etc.)
}
I use itand I think it's

Syntax

43.Exponentiation syntax

intermediate

There is a shortcut syntax for writing large numbers with many zeroes using the e character. The left-hand side number defines the leading number and the right-hand side number of positions the floating-point will move to the right.

1e3; // 1000
1E3; // 1000
3e4; // 3000
2e12; // 2000000000000
0.1e2; // 10

2.13 * 1e6; // 2130000
typeof 1e2; // 'number'
I use itand I think it's

44.Hexadecimal numbers

intermediate

Hexadecimal numbers use 16 distinct symbols (0-F) and are commonly used for memory addresses, web-pages color etc. Hexadecimal number syntax uses a leading zero followed by a letter x and hexadecimal number (only radix 16 - 0123456789ABCDEF values are accepted).

0xa; // 10
0Xa; // 10
0x15f; // 351
0xG // SyntaxError: Expected number in radix 16

0x2 * 0xb; // 22
typeof 0xa; // 'number'
I use itand I think it's

45.Binary numbers

intermediate

Binary numbers use 2 distinct symbols (0-1) and are the basis of all digital systems. Binary number syntax uses a leading zero followed by a letter b and binary number (only radix 2 - 01 values are accepted).

There are a number of algorithms that, with the help of binary numbers, solve complex problems elegantly.

0b1000; // 8
0B1000; // 8
0b2; // SyntaxError: Expected number in radix 2

0b100 * 0b100; // 16
typeof 0b101; // 'number'
I use itand I think it's

46.Octal numbers

intermediate

Octal numbers use 8 distinct symbols (0-7). Octal number syntax uses a leading zero followed by a letter o and octal number (only radix 8 - 01234567 values are accepted).

0o77; // 63
0o77; // 63
0o8; // SyntaxError: Expected number in radix 8

0o71 * 0o5; // 285
typeof 0o1; // 'number'
I use itand I think it's