Matthias Dittgen

August 18, 2021

ES6 Weirds

I am currently working in a React project and while I was a fan of (Vanilla) Javascript just as it was, I’ve got more and more used to the ES6 syntax, primarily all the shortcuts. Also at the company I am working for, we are trying to write ‘clean code‘ and we have static code analysis using Sonarqube with a tough quality gate that consists of compliance with a lot of rules.

But every now and then I stumble into some weird situation and I might update this post whenever I find more of these. Maybe my findings are useful for you as well.

Arrow functions»

I enjoy arrow functions especially whenever I am close to functional programming, writing e.g. pure functions feels just like math.

When an arrow function has a single argument, only, one can ommit braces, but we don’t.

const addOne1 = a => a + 1;
const addOne2 = (a) => a + 1;

const sum1 = a, b => a + b; // Syntax error
const sum2 = (a, b) => a + b;

const sum3 = (a, b) => {
  return a + b
};

Speaking of braces, if the arrow function directly returns a result, there’s no need to open up a curly braces block and explicitly return the result.

When the result is an object literal, the JS interpretor can’t distinguish this from a function body. One needs additional braces around the curly braces. And one can omitt object keys, when the variable names have already the desired name.

const point = (x, y) => {
  x: x,
  y: y
}; // syntax error

const point = (x, ypsilon) => ({
  x,
  y: ypsilon
});

Precedence Rules»

Conditional (ternary) Operator»

Because the … + … operator has a higher precedence than the ternary … ? … : … operator, it gets evaluated first. So putting the ternary into braces is sometimes a good decision.

const asAbsUrl = () => "/some/path/";
const foo = "bar";

console.log(asAbsUrl() + foo ? `#foo/${foo}` : ""); // #foo/bar
console.log(asAbsUrl() + (foo ? `#foo/${foo}` : "")); // /some/path/#foo/bar

You can read about all Operator Precedences at the MDN Web Docs.

And if you stumble about the Associativity, which for the ternary operator is right-to-left in Javascript, but left-to-right in PHP, I can recommend this question at stackoverflow.

console.log(true ? "true" : false ? "t" : "f"); // true
console.log(true ? "true" : (false ? "t" : "f")); // true
console.log((true ? "true" : false) ? "t" : "f"); // t
echo (true ? 'true' : false ? 't' : 'f'); // 't' (*)
echo (true ? 'true' : (false ? 't' : 'f')); // true
echo ((true ? 'true' : false) ? 't' : 'f'); // 't'

// (*) PHP Deprecated:  Unparenthesized `a ? b : c ? d : e` is deprecated

Nullish Coalescing Operator»

Do you know this one? When I first saw this ?? operator, I thought, this is not the Javascript I know. It took some google searches to find out its name and semantic.

First I thought it would be a short for a ternary like this.

let maybeNull = null;
console.log(!!maybeNull ? maybeNull : "something else"); // something else
console.log(maybeNull ?? "something else"); // something else

maybeNull = 'not null';
console.log(!!maybeNull ? maybeNull : "something else"); // not null
console.log(maybeNull ?? "something else"); // not null

But it is called ‘Nullish’ Coalescing Operator because it checks for null, not boolean false. Its Associativity is left-to-right and its Precedences is just one level above the ternary operator, but still far below e.g. +.

const n = null;
const foo = "bar";

console.log(      n??1); // 1
console.log("a" + n??1); // "anull"

Deconstruction»

Another ES6 thing I use a lot is the spread syntax for Deconstruction of objects and arrays. And I just recently stumbled about something I couldn’t read right away. So there was the spread operator directly in front of the ternary operator.

const t = true;
const f = false;

console.log({...(t ? {foo:'bar'} : null})); // {foo: 'bar}
console.log({...t ? {foo:'bar'} : null}); // {foo: 'bar}
console.log({...f ? {foo:'bar'} : null}); // {}

But at MDN you’ll not the ‘spread operator’ in the table of Precedences.

Note that spread syntax is intentionally not included in the table — because, to quote an answer at Stack Overflow, “Spread syntax is not an operator and therefore does not have a precedence. It is part of the array literal and function call (and object literal) syntax.”

This explains also why you could use it also in a function call like this

let args = null;
console.log(...args || []); // no output
console.log(...args || ['foo', 'bar']); // foo bar

args = ['foo', 'bar'];
console.log(...args || []); // foo bar

Nesting Ternary Operators»

In React context writing components as functions it is often nice to use the ternary operator. It’s in the eye of the beholder if this enhances readability or not. And while our SonarQubes Quality gate doesn’t like nesting ternary operators, I would sometimes wish it would.

In combination with having lines not exceeding a character limit, you can break lines at the operator.

const isItAorB = (a, b) => a
  ? "It's A."
  : b
    ? "It's not A, but B."
    : "It is neither the one nor the other."
;

// JSX
const getMeSomeJSX = (link, text) => link
  ? <a href={link}>{text}</a>
  : text
    ? <span>{text}</span>
    : ""
;