JavaScript

Aliases
  • javascript
  • js
  • JS
Image of Author
September 16, 2022 (last updated September 18, 2024)

See also my notes on TypeScript, Nodejs, and Deno for specifics on those technologies.

Decorators

https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841

https://github.com/tc39/proposal-decorators

Fake promises

The quick method is using Promise.resolve. This will resolve as a Promise "immediately".

async function test() {
  const getter = () => Promise.resolve('hi')
  const x = await getter()
  return x // 'hi'
}

If you want to control how long a promise takes to resolve, say for testing purposes, you can introduce a controlled timeout.

function fakePromise(value, timeoutInMs) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(value), timeoutInMs);
  });
}

async function test() {
  const getter = fakePromise('hi', 1000)
  const x = await getter()
  return x // 'hi'
}

setTimeout will call it's callback after timeoutInMs. It's callback is the promise's resolve callback. The resolve callback takes as a parameter the data it will resolve with, which in this case is the provided value data.

JSDoc

JSDoc

Dates

// returns a Unix timestamp aka Epoch time aka POSIX time.
Date.now() // 1719992541975

// returns a Date object
new Date() // 2024-07-03T07:45:03.342Z

// The above output is the same as calling the following
// This is ISO 8601 format, it is always in UTC, denoted by the Z
(new Date()).toISOString() // 2024-07-03T07:45:03.342Z
// .toJSON() returns the same value

// toString
(new Date()).toString()

If you want to create a today and yesterday you need to use getDate instead of getDay, since the former returns day of the month and the latter is the day of the week.

const today = new Date()
const yesterday = new Date(today)
yesterday.setDate(today.getDate() - 1)

This works for month, year, etc. Subtracting beyond, e.g., the first month, will correctly set to the last month of the previous year.

Library Pattern

Library Pattern in JavaScript and TypeScript

Barrel Pattern

Barrel Pattern in JavaScript and TypeScript

optional chaining and nullish coalescing

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

const x = {a: {b: 1}}
const y = x?.a?.b ?? 0

These two operators, ?. the optional chaining operator, and ??, the nullish coalescing operator, are similar in purpose to the ternary operators, e.g., x ? y : z.

It is interesting to note that the right-hand side of ?? is only set when the left-hand side is null or undefined, and not for anything falsey, like 0 or the empty string. ?? is a more robust way to ensure a value than || since you can now support values like 0 or empty string as valid and only override with a default value when the input is truly undefined (or null).

bind this

From MDN bind docs > Creating a bound function,

A common mistake for new JavaScript programmers is to extract a method from an object, then to later call that function and expect it to use the original object as its this (e.g., by using the method in callback-based code).

I'm not a new programmer and make this mistake every time I return to class-heavy code. Here's an example.

class A {
  b;

  constructor() {
    this.b = "b";
  }

  getB() {
    return this.b;
  }
}

const a = new A();
const bound = a.getB.bind(a);
const bound2 = () => a.getB();
const unbound = a.getB;

console.log(a.getB()); // 'b'
console.log(bound()); // 'b'
console.log(bound2()); // 'b'

console.log(unbound());
// TypeError: Cannot read properties of undefined (reading 'b')

Why does JS allow this behaviour? The answer is, first, that classes are syntactic sugar on top of the way javascript really handles instances, methods, and inheritance. Second, the way JavaScript really handles this is via the prototype chain, which means you can inherit "methods" from any object in your prototype chain. Under this particular paradigm, it makes sense for this to default to the object calling the function, and not the object defining the function (which could be anywhere along the prototype chain). This means that "unbound" functions such as a.getB expect to be called outside of the object that it was created in, with a dynamic this value. Unbound functions are more flexible in the prototypal-inheritance paradigm than in more 'normal' class-encapsulation paradigm.

The upside of all of that is flexibility. I.e., you can capture unbound function, making certain types of code reuse possible. The downside is you have to pay attention to when you bind/unbind functions.

Log an object of arbitrary depth

console.dir(obj, { depth: null } will log an object at any depth

typeof

The typeof operator returns a string indicating the type of the operand, aka, the entity being type-checked.

console.log(typeof 1);
// => "number"

This is a great way to safely check for the existence of a variable that might not exist. For example, modern JS/TS uses Server-Side Rendering (SSR). That means the window and document don't yet exist. Something like, window.onload = () => ... would cause a server-side failure, since window is not yet defined. Wrapping the call in if (window) ... does not solve the problem because the successful evaluation of the if-clause requires evaluating window, which is still undefined. This is why typeof is so useful in this scenario

if (typeof window != 'undefined') ...

One final gotcha, !!(typeof window) == !!'undefined' == true. That is, 'undefined' is a string, not an empty, falsey string, a truthy string. You need to explicitly compare again the string 'undefined' for the guard clause to succeed.