Y U NO USE the JS native APIs?

Bruno Noriller - Jan 14 '23 - - Dev Community

Maybe you’re stuck in the ES5 or under a rock for a long time… basically the same thing.

But JS gets more toys for us to use basically every year, with a lot more to come. And since I know people that aren’t using it, I’ll try to highlight here some of the APIs that I can’t live without anymore.

2020

Nullish coalescing operator (??)

You might know the AND (&&) and OR (||) operators, but you know that one case like:

let number = null; // zero being a valid number
// something happens
number = 0;

// check if it's false
if (!number) {
    throw new Error('oops, zero is also falsy!');
}

// this will check if it's null or undefined
if(number ?? true){
    throw new Error('now, only null or undefined will throw!')
}

// usually you would use like
const myPossibleNullishValue = someValue ?? 'value if null or undefined'

// you can also do this:
function ItsAError(){ throw new Error("it's a me, error!") }
const myPossibleNullishValue = someValue ?? ItsAError();
// this way you can validate if the value is not null or undefined as you assign it.
Enter fullscreen mode Exit fullscreen mode

Optional chaining (elvis operator, ?.)

No more object && object.prop1 && object.prop1.prop2 ...

const object = {};

// ok, so: as long as object exists, then object.anything won't throw
// object.anything will be undefined if anything doesn't exists, but that's it
// object.anything.anotherThing however, this will throw because anything is undefined
// all this to say that, you start chaining from the objects that may not exist
const myValue = object
  .prop1
  ?.anything
  ?.anotherThing
  ?.prop2 ?? 'combine with nbullish coalescing for when the value is undefined!';

// it doesn't end here!
// you can chain multiple things:
const test = {
  arr: [1, 2, 3, 4],
  function: () => 'hello!',
  obj: {
    something: 'else'
  }
}

// arrays
test.arr?.[0] ?? 'oops' // 1
test.notArr?.[0] ?? 'oops'; // oops

// functions
test.function?.() ?? 'oops' // hello!
test.notFunction?.() ?? 'oops' // oops

// objects
test.obj?.['something'] ?? 'oops' // else
test.notObj?.['something'] ?? 'oops' // oops
Enter fullscreen mode Exit fullscreen mode

2021

Promise.any

I’m sure you already had to use Promise.race, but sometimes you don’t care that one promise fails, you just want the first that actually resolves. In this case, you use Promise.any.

const maybe = async (n) => {
  const random = Math.random() > 0.8;
  return Promise[random ? 'resolve' : 'reject'](random ? `yes! ${n}` : `nope =/ ${n}`)
};

const coisa = await Promise.any([
  maybe(1),
  maybe(2),
  maybe(3),
  maybe(4),
])
  .then(val => {
    // on the first one that resolves...
    console.log(val) // yes! n
  })
  .catch(err => {
  // if all fails...
  console.log(err.errors) // [ 'nope =/ 1', 'nope =/ 2', 'nope =/ 3', 'nope =/ 4' ]
});
Enter fullscreen mode Exit fullscreen mode

Number separators (_)

What’s this number: 123456789?

How about this: 123_456_789?

That’s it. Just a little quality of life for developers, if you’re using big numbers, you can use the separator to be easier to read.

BTW… this is also valid: 1_2_3_4_5_6_7_8_9 but, for obvious reasons, don’t do that! As long as you don’t use it before/after the number it’s valid. So make sure to put the separator in the right place, please!

String.replaceAll

While we all love RegExp, sometimes we really don’t need to pull out the big guns…

'abbbaab'.replaceAll('b', 'x') // 'axxxaax'
Enter fullscreen mode Exit fullscreen mode

2022

Classes: private and static

Functional is all the rage right now, but sometimes you need an old but still good class… well, it’s better than ever to work with classes in vanilla JS.

Static values and functions are those that live outside of any object instance. It’s something global and has many uses.

And now we have true private fields and functions. You might have seen and used _underscores to say to others that something was to be private, now you can just use # and have it truly be private.

class Counter {
  static #privateTotal = 0

  constructor() {
    Counter.#add();
  }

  static #add() {
    Counter.#privateTotal++;
  }

  remove() {
    Counter.#privateTotal--
  }

  static get total() {
    return Counter.#privateTotal
  }

}

const number1 = new Counter();
const number2 = new Counter();
const number3 = new Counter();
const number4 = new Counter();
Counter.total2 //?
const number5 = new Counter();
console.log(Counter.total); // 5
number1.remove();
console.log(Counter.total); // 4

Counter.add(); // not a function
Counter.#add(); // SyntaxError: Private field '#add' must be declared in an enclosing class
console.log(Counter.privateTotal); // undefined
console.log(Counter['#privateTotal']); // undefined
console.log(Counter.#privateTotal); // SyntaxError: Private field '#privateTotal' must be declared in an enclosing class
Enter fullscreen mode Exit fullscreen mode

String/Array.at

You probably with calluses from doing arr[arr.length -1] for when you want the last element or something like that… well, no more:

const arr = [1, 2, 3, 4, 5]
const str = 'hello world'

console.log(arr.at(-1)) // 5
console.log(str.at(-1)) // d
Enter fullscreen mode Exit fullscreen mode

This is so simple, yet so good. Satisfying!

So… Y U NOT using them?

If you have any transpiling step in your process, then you just have to check for you to use the new APIs and if any aren’t compatible with your target environment, then it will either polyfill or just translate to an uglier, more verbose version of the same thing.

For us, developers, we can just use the newest toys and just let the compilers do their thing to support whatever toaster or palmtop running your code.

Now, tell me which ones you’re already using and which ones you’re now facepalming yourself for not using till now.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .