Javascript: advanced

Javascript: advanced

This is already my 10th article about javascript's programming syntax. Today, I'm stepping into some of the advanced features that appeared with ES6+ revisions. Read it carefully since many of these concepts are fundamental if you're planning to learn React  for instance.

The following features appeared with latest javascript revisions (ES6 and beyond).

Template literal string

This operator is similar to $"" in C# as it allows you to create interpolated strings.
The syntax is a bit different here as show below.

const car = {
    model: 'Toledo',
    vendor: 'Seat'
};

// Use ${} inside back ticks to interpolate data
console.log(`${car.vendor} ${car.model}`); // Seat Toledo

Destructuring

Unpacks values from arrays or objects into distinct variables.

// Array destructuring
let [x, y] = [24, -5];
console.log(x, y); // 24 -5

[x, y] = [8, 6, 8]; // remaining items are ignored
console.log(x, y); // 8 6

// Works on any iterable
let [pair1, pair2] = new Map([
    ['H', 'Hydrogen'],
    ['O', 'Oxygen'],
]);
console.log(pair1, pair2); // ['H', 'Hydrogen'], ['O', 'Oxygen']

// Object destructuring (since ES2018)
const person = { name: 'Oliver', age: 25 };
let { name, age } = person;
console.log(name, age); // 'Oliver' 25
person.age = 24; // has no effect on destructured items
console.log(name, age); // 'Oliver' 25

Important: when using object destructuring, keep in mind that you're collection the properties of an input object. So the variables names used on left-hand necessarily point to a property with the same name. You can use : to specify the target variable if you want to use a different name.

You can use 2 sytaxes : binding pattern and assignment pattern.

const car = { vendor: 'Fiat', model: 'Punto', mileage: 14578 };

// binding pattern requires 'var', 'let', or 'const'
// 'mileage' receives the value
const { mileage } = car;

let carProperties = [];
// assignment pattern requires parenthesis
// left hand declares the target of assignment thanks to ':'
({ vendor: carProperties[0], model: carProperties[1] } = car);
console.log(carProperties); // ['Fiat', 'Punto']

Finally, note that a destructured property can have a default value, used if input value is undefined or absent.

const [x = 0] = []; // x = 0
const {x = 0, y = 1} = { x: undefined, y: null }; // x = 0, y = null

Rest operator

Use rest operator (...rest) to end destructuring and collect all remaining properties of an object.

const [a, b, ...remaining] = [24, -5, 8, 6, 8]; 
console.log(a, b, remaining); // 24 -5 [8, 6, 8]

// You can also use binding pattern as the rest property
// don't forget that you destructure input object, so here you read the length
// property of input array, to use it later in a new const with the same name
const [x, y, ...{ length }] = [24, -5, 8, 6, 8];
console.log(x, y, length); // 24 -5 1

Spread operator

Syntactically similar to Rest operator, Spread syntax can be used to expand elements from an object or an array into a new array or object.

const firstCounts = [0,1,2];
const allCounts = [...firstCounts,3,4,5];
console.log(allCounts); // [0,1,2,3,4,5]

// Handy when passing arguments to a method
const dateFields = [1970, 0, 1]; // 1 Jan 1970
const d = new Date(...dateFields);

// You can also use it to copy an arra
let copy = [...firstCounts]; // same as firstCounts.slice()

// It works with objects as well. Here, we merge two objects
const engine = { power: '120hp', cylinders: 8 };
const design = { doors: 5, length: '9ft', width: '4ft' };
const car = { ...engine, ...design };

Object literal improvements

For reminder, object literals let you create an object on the fly, without the class keyword.

var car = {
  fuel: 'SP95',
  model: '208',
  vendor: 'Peugeot',
  mileage: 125478,
  printMileage: function() {
    console.log(mileage);
  }
};

ES6 improved these declarations in many ways:

// initialization from variables
// no need to write repetitive things like 'a: a, b: b'
const a = 3, b = 'Notre Dame';
const myObject = {
    a // same as a:a
    b // same as b:b
}

// shortened method definition
const robot {
    // same as 'moveLeft: function(d) {}' in ES5
    moveLeft(d) { /* code */ },
    // or arrow syntax
    // same as 'moveRight: function(d) {}' in ES5
    moveRight: (d) => /* code */
}

Null coalescing operator

Similar to C# but here, the ?? operator also works with undefined.

let a = null ?? "default";
let b = undefined ?? "value";
console.log(a, b); // default value

Null coalescing assignment

With almost the same syntax, you can set the value of a variable if it is null or undefined

let b = null;
let a ??= "default";
let b ??= "value";
console.log(a, b); // default value

Optional chaining

Similar to C# but returns undefined instead of null.

const obj = { 
    name: 'John', 
    house: {
        address : '45 johnson street',
        city: 'Malibu'
    },
    dog : null,
};
console.log(obj.house.garage?.surface); // undefined
console.log(obj.dog?.name); // undefined

Symbol

Symbols solves an issue that appeared with the flexibility of javascript, ahich allows you to add keys into your objects from all over the place.
At some point, one might override an existing key by redefining it again which would obvisouly introduce issues in code.

A Symbol is a new type of primitive in ES6 and its purpose is to create unique keys that you can then use to in your object. In a sense, it comes close to an enum value with a unique reference.

// Consider the following object
const jet {};
jet["company"] = 'Js arilines';
console.log(jet); // { company: 'Js arilines'}

// Anyone can alter existing key in the codebase
jet["company"] = 'Airbus';
console.log(jet); // { company: 'Airbus'}

// To prevent this type of accident, use Symbols
// A symbol can be declare with Symbol() with an optional
// input description that you can reuse later to provide context
// The description does not identify the symbol, it it is purely informative
let company = Symbol("The airline company");
// Now you can add this as a key in the object
jet[company] = 'Js airline';

console.log(jet); // { company: 'Airbus', [Symbol(The airline company)]: 'Js airline'}

// Now you can only access the property you created with THE symbol
console.log(jet[company]); 
console.log(jet[Symbol("The airline company")]); // undefined 

// Here is another example
const color = {};
let red = Symbol('R');
let green = Symbol('G');
let blue = Symbol('B');
color[red] = 145;
color[green] = 0;
color[blue] = 60;
// unless you have access to 'red', 'green', 'blue',
// you can't edit color[red], color[green] and color[blue]