Javascript ways

Technical, Insights

title: Javascript ways created_at: 2020-11-15T14:52:16.823Z updated_at: 2023-04-01T14:52:16.823Z tldr: Shorthands, macros, cannot understand, NaNaNaN whatever is_published: true star: false category: Technical, Insights share_type: share

Note!

Please do not use this where people are reading your code on a day to day basis. These are cheeky and cool yes!. But, when people see this on a day to day basis they will curse you. Don't get git blamed 🙏

Filter null, undefined

[1, 2, null, 5, undefined].filter(Boolean);
// [1, 2, 5]
Boolean is an helper class, so Boolean(value) return true for all valid elements

Create an array of n elements

const array = new Array(n).fill(0).map((_, i) => i);
Create an array with n elements, fill it with 0

Add a helper prototype

Number.prototype.add = function (n) {
  return this + n;
};

(1).add(2); // 3
Almost everything in JS is object, you can extend Number, String ... like any other object

Calling functions with backtics

function saveName(name) {
  this.db.save(name);
}

saveName`${this.firstName} ${this.lastName}`;
MDN Docs on Template literals

Finally doesn't wait

function foo() {
  let r = 0;
  try {
    r = 1;
  } finally {
    r = 2;
  }

  return r;
}

foo(); // 2
The try catch finally spec

Old school labels

cat: {
  console.log("meow");
  break cat;
  console.log("woff");
}
// meow
// undefined

let x = [];
outter: for (let i = 0; i < 4; i++) {
  inner: for (let j = 0; j < 4; j++) {
    if (i + j === 2) {
      continue outter;
    }
    x.push(i + j);
  }
}

console.log(x); // [0, 1, 1, 3, 4, 5, 6]
labels work in javascript But, if you use it people around will beat you, seriously!

Noodles and curry

// basic currying
function makeAdderForA(a) {
  return function (b) {
    return a + b;
  };
}

const adderFor_2 = makeAdderForA(2);
console.log(adderFor_2(3); // 5

// noodles, make me cook instantly!
(function () {
  document.onreadystatechange = () => {
    if (document.readyState === "complete") {
      document.querySelector("html").classList.remove("veil");
    }
  };
})();
functions returning functions is currying, and functions invocating itself is IIFE. I call it noodels!

Infinite Pings

JS has a recursion limit of around 10000 calls, we can rely on generators to escape. Your browser will break, careful!

// Recursion error
function ping(n) {
  console.log('ping', n);
  return pong(n + 1);
}

function pong(n) {
  console.log('pong', n);
  return ping(n + 1);
}

// crash your browser
const actors = {};
const messageQ = [];

const postToMessageQ(name, msg) => messageQ.push([name, msg]);

const run => {
  while (queue.length) {
    const [name, msg] = queue.shift();
    actors[name].next(msg);
  }
}

function* ping() {
  let n;
  while (true) {
    n = yield;
    console.log('ping', n);
    send('pong', ++n);
  }
}

function* pong() {
  let n;
  while (true) {
    n = yield;
    console.log('pong', n);
    send('ping', ++n);
  }
}

actors.ping = ping();
actors.pong = pong();
send('ping', 0);

// ping 0
// pong 1
// ping 2
// pong 3
// ...
// to infinity and beyond!
You Don't Know JS: Async & Performance

Can't change me

Getting rid of type coercion

function nonCoercible(val) {
  if (val == null) {
    throw TypeError("nonCoercible shouldn't be called with null or undefined");
  }
  const res = Object(val);
  res[Symbol.toPrimitive] = () => {
    throw TypeError("Trying to coerce non-coercible object");
  };
  return res;
}

// objects
const foo = nonCoercible({ foo: "foo" });

foo * 10; // throws TypeError: Trying to coerce non-coercible object
foo + "evil"; // throws TypeError: Trying to coerce non-coercible object
nonCoercible(["foo"])[0]; // "foo"
Gist, Sergey Rubanov

Arrow functions needs shield to return objects

let f = () => {};
f(); // undefined

let f = () => ({});
f(); // {}
I used to mess this up so many times with react FC and .map functions

Dei, you forgot a semicolon :|

Javascript insers a ; token automatically

function foo() {
  return;
  1;
}
foo(); // undefined

function foo() {
  return 1;
}
foo(); // 1
Rules of Automatic Semicolon Insertion

WTF

JS has character escape sequences

[666]["\155\141\160"][
  "\
\143\157\156\163\164\
\162\165\143\164\157\
\162"
](
  "\141\154\145\
\162\164(666)",
)(666); // alert(666)
alert from Hell

Function typings and merging

when function calls in Typescript are merged, the resulting argument list is an intersection not union

function funA(p: { apples: string; bannans: number }) {}
function funB(p: { apples: string; mangoes: string }) {}

const funC: typeof funA & typeof funB = ({ apples, mangoes }) => {};
// error: Property 'mangoes' does not exist
In typescript when we union objects the resulting is an superset of the object values, but when we union functions the resulting is the intersection on the function parameters. This is how all the type system work. Further reading difference between variance covariance and contravariance

Typescript enums to objects

TS has a really odd way of converting of enums to plain js

// with no variable assignee
enum THEME {
    DARK,
    LIGHT,
}

// in JS
var THEME;
(function (THEME) {
    THEME[THEME["DARK"] = 0] = "DARK";
    THEME[THEME["LIGHT"] = 1] = "LIGHT";
})(THEME || (THEME = {}));
// {0: "DARK", "DARK": 0, 1: "LIGHT", "LIGHT": 1}; so we can do THEME[0];

// but when you assign a string
enum THEME {
    DARK = 'apple',
    LIGHT = 'mangoes',
}

// in JS
var THEME;
(function (THEME) {
    THEME["DARK"] = "Yagami";
    THEME["LIGHT"] = "L";
})(THEME || (THEME = {}));
// {DARK:"Yagami", LIGHT: "L"}; we can't do THEME["L"]?

Component as function in react, wait wt?

You can use components as functions in react, store it in Objects and call it in render

const iconRecord = {
  night: NightIconJSX,
  day: DayIconJSX,
};

const App = () => {
  return (
    <div>
      {object
        .values(iconRecord)
        .map((icon) => icon(/* you can pass in props as object {}*/))}
    </div>
  );
};

Further reading