Skip to main content

JavaScript

npx code-complexity . --limit 20 --sort ratio - https://www.kevinpeters.net/the-fastest-way-to-understand-new-code-bases

In JavaScript typeof null is "object".

https://stateofjs.com/en-us/

Libraries

Validation

See comparison here: https://github.com/colinhacks/zod#comparison

JSDoc

https://jsdoc.app

https://devhints.io/jsdoc

TC39

https://github.com/tc39

https://tc39.es

ECMAScript Language Specification: https://tc39.es/ecma262/

ECMAScript Proposals: https://github.com/tc39/proposals

https://twitter.com/tc39

== vs === and != vs !==

https://stackoverflow.com/a/55822553/4034572

null == undefined // true
null === undefined // false

null != undefined // false
null !== undefined // true

console

Spec: https://console.spec.whatwg.org/

Use %i (integer), %f (float), %s (string) for type conversions: https://twitter.com/addyosmani/status/1535706659128868864

console.group

https://developer.mozilla.org/en-US/docs/Web/API/Console/group

console.group('label')
console.log(...)
console.log(...)
console.groupEnd()

console.time

console.time('label')
// ...
console.timeLog('label')
// ...
console.timeEnd('label')

This is for React Native.

/**
* Use it to print objects to the console preserving undefined values.
* Usage: `console.log('User', prettyPrint(user))`.
* From https://stackoverflow.com/a/50100175/4034572.
*/
export function prettyPrint(object: any): string {
return JSON.stringify(
object,
(k, v) => (v === undefined ? '__undefined' : v),
2
).replace(/"__undefined"/g, 'undefined')
}

Object

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object

delete operator

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

Object.entries()

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries

const user = {
name: 'Joe',
age: 42,
}
for (const [key, value] of Object.entries(user)) {
console.log(`${key}: ${value}`)
}

Object.assign()

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Can be used to copy an object changing a property without modifying it.

Eg to toggle 'complete' of an object in a Redux reducer without modifying it:

const newTodo = Object.assign({}, todo, {complete: !todo.complete})

This creates a new object {}, merges all the properties of the 'todo' object into this new object, and then overrides the 'complete' property. The original 'todo' object is not modified, so the reducer is pure.

Error

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error

Error('message') and new Error('message') is the same.

When Error is used like a function -- without new, it will return an Error object. Therefore, a mere call to Error will produce the same output that constructing an Error object via the new keyword would. source

Rethrow an error but with a different message: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Error#rethrowing_an_error_with_a_cause

Promise

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

https://devdocs.io/javascript-promise/

Api.fetchUser = function () {
return new Promise((res, rej) => {
setTimeout(() => {
res(user)
}, 2000)
})
}

Promise.reject()

return Promise.reject(Error('reason'))

Promise.all() and Promise.allSettled()

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled

  • Promise.all() resolves when (waits until) all promises resolve, and rejects immediately if any promise rejects.
  • Promise.allSettled() resolves when (waits until) all promises have either fulfilled or rejected.
Promise.all([
Api.fetchUser(),
Api.fetchPosts()
]).then(([user, posts]) => {
console.log('user', user)
console.log('posts', posts)
}).catch(error => {
console.log(error)
})
Promise.allSettled([
Api.fetchUser(),
Api.fetchPosts()
]).then(([userResult, postsResult]) => {
console.log('user result', userResult) // {status: "fulfilled", value: {username: 'albert'}},
console.log('posts result', postsResult) // {status: "rejected", reason: Error: some error happened}
})

delay / timeout / sleep

function delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms))
}

function fakeApiCall(): Promise<void> {
return delay(2500)
}
function delay(ms: number): () => Promise<void> {
return () => new Promise((resolve) => setTimeout(resolve, ms))
}

function fakeApiCall(): Promise<void> {
return Promise.resolve().then(delay(2500))
}
function delay<T>(ms: number): (x: any) => Promise<T> {
return (x: T) => new Promise((resolve) => setTimeout(resolve, ms, x))
}

function fakeApiCall(): Promise<number> {
return Promise.resolve(33).then(delay<number>(2500))
}

try-catch only 'catches' errors if you await

function doSomething() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('setTimeout error')
}, 2000)
})
}

async function main() {
try {
doSomething() // <- Missing 'await' here!
} catch (error) {
console.error('try-catch worked :) - error:', error)
}
}

main().then(() => {
console.log('Done!')
})

Running it with node index.js will give:

Done!
node:internal/process/promises:288
triggerUncaughtException(err, true /* fromPromise */);
^

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "setTimeout error".] {
code: 'ERR_UNHANDLED_REJECTION'
}

The try-catch does not have any effect (ie it does not catch the error) and the program crashes due to UnhandledPromiseRejection. Also, "Done!" is printed immediately since we don't wait for doSomething() to finish.

If you add await before doSomething() it works correctly:

try-catch worked :) - error: setTimeout error
Done!

It waits 2 seconds before printing "try-catch worked :) - error: setTimeout error" and then immediately after "Done!".

AbortController

https://developer.mozilla.org/en-US/docs/Web/API/AbortController

https://www.bennadel.com/blog/4200-using-fetch-abortsignal-and-settimeout-to-apply-retry-mechanics-in-javascript.htm

https://stackoverflow.com/a/65805464/4034572

String

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String

danger

substr() is deprecated. Use slice() instead.

startsWith()

endsWith()

Regex

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions

Regex syntax cheatsheet: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet

https://devdocs.io/javascript-regexp/

Name capture groups: https://twitter.com/addyosmani/status/1386031624232456194

In TypeScript use the type RegExp.

RegExp.prototype.test()

MDN

function isValidEmail(email: string): boolean {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ // From https://stackoverflow.com/a/9204568/4034572
return regex.test(email)
}

RegExp.prototype.exec()

MDN

const regex = /abcd/gi
const string = 'something'
regex.exec(string)
// returns an array with the matches or null

String.prototype.match()

MDN

const regex = /abcd/gi
const string = 'something'
string.match(regex)
// returns an array with the matches or null

Dates

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl

Date format

https://stackoverflow.com/questions/3552461/how-do-i-format-a-date-in-javascript

Date.prototype.toLocaleDateString() at MDN

toLocaleString options: https://www.jsman.net/manual/Standard-Global-Objects/Date/toLocaleString

new Date(search.date).toLocaleDateString() // 5/27/2021
new Date(search.date).toLocaleDateString('es-ES') // 27/5/2021

Intl.DateTimeFormat

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat

Important: does not work on React Native Android. You get the error "Can't find variable: Intl". See solutions at https://stackoverflow.com/questions/56943813/using-intl-properly-in-android-react-native-app. Update November 2022: Hermes does support Intl, see https://hermesengine.dev/docs/intl. Hermes is the default since 0.70 - see https://reactnative.dev/blog/2022/09/05/version-070#hermes-as-default-engine and https://reactnative.dev/blog/2022/07/08/hermes-as-the-default. On Expo, since SDK 47 - see https://blog.expo.dev/expo-sdk-47-a0f6f5c038af.

Example from https://stackoverflow.com/a/3552493/4034572:

export function formatDate(dateNumber: number): string {
const dateObject = new Date(dateNumber)
const year = new Intl.DateTimeFormat('en', { year: 'numeric' }).format(
dateObject
)
const month = new Intl.DateTimeFormat('en', { month: 'short' }).format(
dateObject
)
const day = new Intl.DateTimeFormat('en', { day: '2-digit' }).format(
dateObject
)
return `${day} ${month} ${year}`
}

formatDate(1583495987) returns 19 Jan 1970.