A few handy JavaScript tricks
Tags: javascript, promises
Published: 2020-12-01 11:45:01

<!-- by @noseratio for DEV.TO: https://dev.to/noseratio/a-few-handy-javascript-tricks-an9 -->

I'd like to document a few neat JavaScript tricks and patterns I've recently learnt from Twitter and other online resources (which I sadly haven't kept track of). All the credits go to the online JavaScript community.

## Table Of Contents
  * [`class` is an expression, what it extends is also an expression](#class-is-expression)
  * [`this` in static class methods](#this-in-static-class-methods)
  * [Invoking an IIFE without extra brackets](#invoking-an-IIFE)
  * [Invoking an async IIFE without extra brackets](#invoking-an-async-IIFE)
  * [Destructuring of a function argument inline](#destructuring)
  * [Partial destructuring of a function argument inline](#partial-destructuring)
  * [Using expressions in `switch`](#expressions-in-switch)
  * [Passing a non-function object as event handler to `addEventListener`](#non-function-event-handler)
  * [Checking if a variable is of specific type](#variable-of-specific-type)
  * [Checking if a variable is `nullish` (i.e., `null` or `undefined`)](#null-or-undefined)
  * [Converting to primitive types with `Symbol.toPrimitive`](#Symbol-toPrimitive)
  * [A mnemonic way of ignoring promise errors (where applicable)](#ignoring-promise-errors)
  * [Thenables can be useful side-by-side with promises](#thenables)
  * [Telling which promise has settled first in `Promise.race`](#promise-settled-first)
  * ["Promisifying" a synchronous function call to defer exception handling](#promisifying-function-call)
  * [`Symbol.species` can be useful when extending standard classes](#Symbol-species)
  * [`await` can be used inside string templates](https://dev.to/noseratio/await-inside-javascript-template-strings-3kbj)
<a name="class-is-expression"></a><hr>

#### `class` is an expression, what it extends is also an expression

Similar to `function funcName() { ... }`, `class className { ... }` is an expression which can be assigned to a variable or passed over as a function argument. And `className` here can be optional as well, like with anonymous functions. More so, the base class is also an expression. For example, the following is possible:

```JavaScript
class Base1 {
  whatAmI() { 
    return 'Base1';
  }
}

class Base2 {
  whatAmI() { 
    return 'Base2';
  }
}

const createDerivedClass = base => class extends base {
  whatAmI() {
    return `Derived from ${super.whatAmI()}`;
  }
};

const Derived1 = createDerivedClass(Base1);
// output: Derived from Base1
console.log(new Derived1().whatAmI());

const Derived2 = createDerivedClass(Base2);
// output: Derived from Base2
console.log(new Derived2().whatAmI());
```

This can be useful for dynamic compositions of class inheritance trees, including *mixins*. I've learnt about it from Justin Fagnani's excellent ["Mixins and Javascript: The Good, the Bad, and the Ugly."](https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes)
<a name="this-in-static-class-methods"></a><hr>

#### Conveniently, `this` in static class methods refers to the class itself 

Thus, polymorphism is possible for static methods, like with `oncreate` method below:

```JavaScript
// Base
class Base {
  static create() { 
    const instance = new this();
    this.oncreate(instance);
    return instance; 
  }

  static oncreate(instance) { 
    console.log(`Something of the base class ${
      Base.name} has been created.`); 
  }
}

// Derived
class Derived extends Base {
  static oncreate(instance) { 
    console.log(`It's a new instance of ${
      Derived.name}, all right!`); 
  }
}

// output: Something of the base class Base has been created.
const base = Base.create(); 

// output: It's a new instance of Derived, all right!
const derived = Derived.create(); 
// output: true
console.log(derived instanceof Derived);
```
I learnt about `new this()` when I stumbled upon [this tweet](https://twitter.com/RReverser/status/695678489937186816).

<a name="invoking-an-IIFE"></a><hr>

#### Invoking an IIFE (Immediately Invoked Function Expression) without extra brackets

We can use the [`void` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void) for that, where `void` clearly indicates we want to discard the result of an *expression* (which an IIFE itself is):

```JavaScript
void function debug() {
  if (confirm('stop?')) debugger;
}(); 
```

I believe it's more readable and mnemonic than wrapping the function with brackets:

```JavaScript
(function debug() {
  if (confirm('stop?')) debugger;
})();
```

If we do need the result:

```JavaScript
const rgb = function getColor(color) {
  return { 
    red: '#FF0000',
    green: '#00FF00',
    blue: '#0000FF'
  }[color];
}(car.color); 
```
<a name="invoking-an-async-IIFE"></a><hr>

#### Invoking an `async` IIFE (Immediately Invoked Function Expression)

Similarly to the above, we don't need the wrapping brackets:

```JavaScript
await async function delay() {
  const start = performance.now();
  await new Promise(r => setTimeout(r, 1000));
  console.log(`elapsed: ${performance.now() - start}`);
}();
```
<a name="destructuring"></a><hr>

#### Destructuring of a function argument inline

```JavaScript
function output ({firstName, lastName}) {
  console.log(firstName, lastName);
}

const person = {
  firstName: 'Jane',
  lastName: 'Doe'
};

output(person);
```
<a name="partial-destructuring"></a><hr>

#### Partial destructuring of a function argument inline

```JavaScript
function output ({firstName, ...rest}) {
  console.log(firstName, rest.lastName, rest.age);
}

const person = {
  firstName: 'John',
  lastName: 'Doe',
  age: 33
};

output(person);
```
<a name="expressions-in-switch"></a><hr>

#### Using expressions in `switch`

```JavaScript
const category = function getCategory(temp) {
  // the first `case` which expression is `true` wins
  switch(true) {
    case temp < 0: return 'freezing';
    case temp < 10: return 'cold';
    case temp < 24: return 'cool';
    default: return 'unknown';
  }
}(10);
```
<a name="non-function-event-handler"></a><hr>

#### Passing a non-function object as event handler to [`addEventListener`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)

The trick is to implement [`EventListener.handleEvent`](https://developer.mozilla.org/en-US/docs/Web/API/EventListener):

```JavaScript
const listener = Object.freeze({
  state: { message: 'Hello' },
  handleEvent: event => {
    alert(`${event.type} : ${listener.state.message}`);
  }
});

button.addEventListener('click', listener); 
``` 
<a name="variable-of-specific-type"></a><hr>

#### Checking if a variable is of specific type

This method works for both primitive value types and their wrapper classes: `String`, `Number`, `Boolean`, `Object`.

Could you predict which console output is common for `s1` and `s2` snippets below? 

```JavaScript
const s1 = 's'; 
console.log(s1 instanceof String);
console.log(typeof s1);
console.log(s1.constructor === String);

const s2 = new String('s'); 
console.log(s2 instanceof String);
console.log(typeof s2);
console.log(s2.constructor === String);
```

I could not, so I've made a [RunKit](https://runkit.com/noseratio/object-constructor):

```Text
s1 instanceof String: false
typeof s1: string
s1.constructor === String: true
s2 instanceof String: true
typeof s2: object
s2.constructor === String: true
```

Interestingly, it's only `s1.constructor === String` and `s2.constructor === String` which are consistently `true` for both `s1` (a primitive string value) and `s2` (an instance of [`String` class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#String_primitives_and_String_objects)). 

[It's even more fun in TypeScript](https://dev.to/noseratio/the-divine-coercion-between-typescript-basic-types-their-wrappers-simple-objects-and-classes-9p7), which may feel odd for a person coming to JavaScript with C# or Java background.

So, to check if variable `s` represents a string, the following works equally well for primitive values and their wrapping class types:

```JavaScript
const isString = s?.constructor === String;
```

We can also make it work across realms (an `iframe` or a popup):

```JavaScript
const isString = s?.constructor.name === 'String';
```

Some may argue that we shouldn't be using class wrappers for primitive values at all. Indeed, we should not. But we have an option to make *our own code* behave correctly when it is called by a 3rd party, no matter if it's given a primitive value or a wrapper class object as an argument.

For example, the following works consistently for all three cases (note the use of [`valueOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf)):

```JavaScript
takeBool(false);
takeBool(Boolean(false));
takeBool(new Boolean(false));

function takeBool(b) {
  if (b?.constructor !== Boolean) throw new TypeError();
  console.log(b.valueOf() === false? "is false": "is true");
}
```
<a name="null-or-undefined"></a><hr>

### Checking if a variable is `nullish` (i.e., `null` or `undefined`)

Traditionally, this is done with *loose equality* operator `==`, for example:

```JavaScript
if (a == null) {
  // a is either null or undefined
  console.log((a == null) && (a == undefined)); // both true 
}
```

This might arguably be [the only meaningful use](https://dorey.github.io/JavaScript-Equality-Table/unified/) of the loose equality `==` operator (as opposed to the *strict equality* operator `===`). 

If however you want to avoid using `==` and `!=` operators by all means, below are some alternative ways of performing the "nullish" check:

```JavaScript
// The nullish coalescing (??) operator returns 
// its right-hand side operand when its left-hand side operand 
// is null or undefined, and otherwise returns 
// its left-hand side operand.

if ((a ?? null) === null) {
  // a is either null or undefined
}

if (Object.is(a ?? null, null)) {
  // a is either null or undefined
}

if (Object.is(a ?? undefined, undefined)) {
  // a is either null or undefined
}

// all standard or properly derived custom JavaScript objects 
// have standard properties like these:
// `constructor`, `valueOf`, `toString`.
// Note though the below doesn't work for exotic cases, 
// e.g. where a = Object.create(null):

if (a?.constructor) {
  // a is neither null nor undefined
}

if (!a?.constructor) {
  // a is either null or undefined
}

if (a?.valueOf === undefined) {
  // a is either null or undefined
}
```

What's nice about the [optional chaining operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators) is that the result is unambiguously `undefined` when `a` is either `null` or `undefined`. This allows for some fancy expressions like this:

```JavaScript
class Derived extends Base {
  constructor(numericArg) {
    // make sure the argument we pass to the base class'
    // constructor is either a Number or DEFAULT_VALUE
    super(function() {
      switch (numericArg?.constructor) {
        case undefined: return DEFAULT_VALUE;
        case Number: return numericArg.valueOf();
        default: throw new TypeError();
      }
    }());
  }
}
```

One notable thing about the [nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator) is that in `a ?? DEFAULT_VALUE` it will pick `DEFAULT_VALUE` when `a` is either `null` or `undefined` (as opposed to `a || DEFAULT_VALUE`, which picks `DEFAULT_VALUE` when `a` is [`falsy`](https://developer.mozilla.org/en-US/docs/Glossary/Falsy)).

<a name="Symbol-toPrimitive"></a><hr>

#### Converting to primitive types with `Symbol.toPrimitive`

The well-know symbol [`Symbol.toPrimitive`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive) defines how an object can be converted to primitive types, as in the example below. Note also the use of [`Symbol.toStringTag`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag):

```JavaScript
class Item {
  #item;

  constructor(item) {
    if (item?.constructor !== Number) throw new TypeError();
    this.#item = item.valueOf();
  }

  [Symbol.toPrimitive](hint) {
    // hint can be "number", "string", and "default" 
    switch (hint) {
      case 'number': 
        return this.#item;
      case 'string': 
      case 'default': 
        return `Item: ${this.#item}`;
      default:
        return null;
    }
  }

  get [Symbol.toStringTag]() {
    return this.constructor.name;
  }
}

const item = new Item(42);
console.log(Number(item));
console.log(String(item));
console.log(item.toString());
console.log(item);

/* Output:
42
Item: 42
[object Item]
Item {}
*/
```
<a name="ignoring-promise-errors"></a><hr>

#### A mnemonic way of ignoring promise errors (where applicable)

```JavaScript
await promise.catch(e => void e); 
```

This literally says: *"void that error"* and it is ESLint-friedly. I see it becoming increasingly useful, to avoid potential troubles with [unhandled promise rejections](https://stackoverflow.com/a/64344718) in Node v15+. For example:

```JavaScript
// • we may want to start workflow1 before workflow2
const promise1 = workflow1();
const promise2 = workflow2();
// • and we may need workflow2 results first
// • if it fails, we don't care about the results of workflow1
// • therefore, we want to prevent 
//   unwanted unhandled rejection for promise1
promise1.catch(e => void e); 
// • observe workflow2 results first
await promise2; 
// • if the above didn't throw, now observe workflow1 results
await promise1;
```
<a name="thenables"></a><hr>

#### Thenables can be useful side-by-side with promises

I've previously blogged [about thenables](https://dev.to/noseratio/we-can-make-any-javascript-object-await-able-with-then-method-1apl). In a nutshell, here's how to create a [`jQuery.Deferred`](https://api.jquery.com/jquery.deferred/)-like thenable object that can be awaited:

```JavaScript
function createDeferred() {
  let resolve, reject;

  const promise = new Promise((...args) => 
    [resolve, reject] = args);

  return Object.freeze({
    resolve, 
    reject,
    then: (...args) => promise.then(...args)
  });
}

const deferred = createDeferred();
// resolve the deferred in 2s 
setTimeout(deferred.resolve, 2000);
await deferred;
```
<a name="promise-settled-first"></a><hr>

#### Telling which promise has settled first in [`Promise.race`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race)

Sometimes we need to know which promise became resolved or rejected first and thus won the race with `Promise.race`, similarly to [`Task.WhenAny`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.whenany?view=net-5.0) in .NET. Linking my [SO answer](https://stackoverflow.com/a/64723870/1768303):

```JavaScript
/**
 * When any promise is resolved or rejected, 
 * returns that promise as the result.
 * @param  {Iterable.<Promise>} iterablePromises An iterable of promises.
 * @return {{winner: Promise}} The winner promise.
 */
async function whenAny(iterablePromises) {
  let winner;

  await Promise.race(function* getRacers() {
    for (const p of iterablePromises) {
      if (!p?.then) throw new TypeError();
      const settle = () => winner = winner ?? p;
      yield p.then(settle, settle);
    }
  }());

  // return the winner promise as an object property, 
  // to prevent automatic promise "unwrapping"
  return { winner }; 
}
```
<a name="promisifying-function-call"></a><hr>

#### "Promisifying" a synchronous function call to defer exception handling 

Credits: [tc39-proposal-promise-try](https://github.com/tc39/proposal-promise-try).

```JavaScript
function ensureEven(a) {
  if (a % 2 !== 0) throw new Error('Uneven!');
  return a;
}

// • this throws:
const n = ensureEven(1);

// • this doesn't throw:
const promise = Promise.resolve().then(() => ensureEven(1));
// • until it is awaited
const n = await promise;

// • alternatively:
const promise = Promise(r => r(ensureEven(1)));
```

Hopefully, soon we'll be able to do:
```JavaScript
const promise = Promise.try(() => ensureEven(1));
```
Until then, we can also use a polyfill like [this one](https://twitter.com/RReverser/status/695678489937186816).

<a name="Symbol-species"></a><hr>

#### `Symbol.species` can be useful when extending standard classes

The well-know symbol `Symbol.species` was definitely little-known to me. [MDN describes it](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/species) as symbol that *specifies a function-valued property that the constructor function uses to create derived objects*.

What it means in reality is that sometimes JavaScript needs to create a fresh instance of an object, i.e., to reproduce an object without cloning. For example, [`Array.prototype.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) creates a new array instance before doing any mapping:

```JavaScript
class UltraArray extends Array {}
const a = new UltraArray(1, 2, 3);
const a2 = a.map(n => n/2);
console.log(a2 instanceof UltraArray); // true
```

It might be tempting to think about such kind of object reproduction this way: 

```JavaScript
const a2 = new a.constructor();
```

In reality though, it's done a bit differently, more like this:

```JavaScript
const constructor = a.constructor[Symbol.species] ?? a.constructor;
const a2 = new constructor();
```

Thus, if we want `map` to use the base class `Array` for a new mapped instance, when `map` is invoked on an object of our custom class `UltraArray`, we can do this:

```JavaScript
class UltraArray extends Array {
  static get [Symbol.species]() { return Array; }
}
const a = new UltraArray(1, 2, 3);
const a2 = a.map(n => n/2);
console.log(a2 instanceof UltraArray); // false
console.log(a2.constructor.name); // Array
```

When could this feature (seemingly not so useful) still be important? My answer would be: *for deriving from and extending the standard [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) class with added functionality like `DeferredPromise`, `AbortablePromise`, etc.* This probably deserves a separate blog post, which I plan to publish soon.

#### I hope you find these tips helpful

I plan to keep this post updated as I discover more fun JavaScript bits and pieces. Consider [following me on Twitter](https://twitter.com/noseratio) if interested in these updates.