Skip to content

Instantly share code, notes, and snippets.

@calebsander
Last active June 30, 2020 19:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save calebsander/b425a41232bf7026847e4c1cc1587f2a to your computer and use it in GitHub Desktop.
Save calebsander/b425a41232bf7026847e4c1cc1587f2a to your computer and use it in GitHub Desktop.
Handy JavaScript shorthands

Arrays

  • Create a new array with n elements, each initialized to x
new Array(n).fill(x)
  • Create a new array with n elements, each initialized as f()
// Imperatively
const a = []
for (let i = 0; i < n; i++) a[i] = f()

// Using map()
new Array(n).fill().map(f) // fill() is needed to initialize all the elements

// For example, to generate an array of 10 random numbers from 0 to 1
new Array(10).fill().map(Math.random)
  • Sum elements in array arr
arr.reduce((a, b) => a + b, 0)
// or, if arr is known to have at least 1 element,
arr.reduce((a, b) => a + b)
  • Count unique elements in an array arr
new Set(arr).size
  • Array.from(iter)
[...iter]
  • Destructure last element of array
// like const [..._, last] = arr
const [last] = arr.slice(-1)
  • Generate all permutations of arr in place (i.e. values returned by the iterator are all arr, but with the items in a different order each time)
const swap = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]]
function* permute(arr, startIndex = 0) {
	if (startIndex === arr.length) {
		yield arr // or arr.slice() if you want to store the permutations
		return
	}
	for (let swapIndex = startIndex; swapIndex < arr.length; swapIndex++) {
		swap(arr, startIndex, swapIndex)
		yield* permute(arr, startIndex + 1)
		swap(arr, startIndex, swapIndex)
	}
}
for (const permutation of permute(arr)) {
	/* process permutation */
}

Maps

  • Map pairs of keys to values
const map = new Map // Map<K1, Map<K2, V>>

// To map (key1, key2) to val
let map1 = map.get(key1)
if (!map1) {
	map1 = new Map
	map.set(key1, map1)
}
map1.set(key2, val)

;// To get what (key1, key2) is mapped to
(map.get(key1) || new Map).get(key2)
  • Keeping track of counts, defaulting to 0
const counts = new Map

// To increment count of item
counts.set(item, (counts.get(item) || 0) + 1)

// To get count of item
counts.get(item) || 0

Objects

  • Setting keys on objects from variables of the same name
// Explicitly setting field
obj.someLongName = someLongName

// Using Object.assign
Object.assign(obj, {someLongName})

// Immutably
obj = {...obj, someLongName}

Function parameters

  • Normally function parameters are passed by position, which requires remembering the order to pass them. However, destructuring makes it easy to pass parameters by value:
// With positional parameters
const foldl = (f, initial, list) =>
	list ? foldl(f, f(initial, list.head), list.tail) : initial

foldl((a, b) => a + b, 0, new LinkedList([1, 2, 3, 4]))

// With named parameters
const foldl = ({f, initial, list}) =>
	list ? foldl({f, initial: f(initial, list.head), list: list.tail}) : initial
foldl({
	list: new LinkedList([1, 2, 3, 4]),
	initial: 0,
	f: (a, b) => a + b
})
  • You can also easily provide default values for any number of parameters, allowing each one to be provided or omitted:
function fun(required1, {optional1 = 1, optional2 = 2, optional3 = 3} = {}) {
	// ...
}

fun('abc')
fun('abc', {optional1: 10})
fun('abc', {optional3: 30})
fun('abc', {optional3: 30, optional2: 20})

Miscellaneous

  • Factorial function (n => n!); don't pass it negative numbers
const fac = n => n < 2 ? 1 : n * fac(n - 1)
  • Treating a method as a function
const chunks = []

// Writing new anonymous function
stream.on('data', chunk => chunks.push(chunk))

// Tempting, but doesn't work
stream.on('data', chunks.push) // this is like calling (chunks.push)(chunk)

// Binding this param
stream.on('data', chunks.push.bind(chunks))
  • Adding block scope to case statements
// Naively, without block scope -> SyntaxError: Identifier 'someVar' has already been declared
switch (val) {
	case 1:
		const someVar = 2
		break
	case 2:
		const someVar = 1
		break
	// ...
}

// With added block scopes
switch (val) {
	case 1: {
		const someVar = 2
		break
	}
	case 2: {
		const someVar = 1
		break
	}
	// ...
}
  • Ignoring results from a request if a newer one has been issued
let searchToken
function search() {
	const token = Symbol()
	searchToken = token
	somethingAsynchronous(response => {
		if (searchToken !== token) return
		
		// process response
	})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment