Joshua's Cheatsheets - General JavaScript Misc. Notes
Light
help

This page covers lots of JS tidbits that I'm having trouble categorizing under other pages. Things on this page might frequently shift around or get moved to other pages.

Forgetful JS

These are things that, for whatever reason, have a hard time sticking in my head. I'm hoping that summarizing some of them and writing them down will help me remember!

Object Destructuring

There are all kinds of destructuring in JS - check out MDN for details. There are lots of advanced ways to use them, but I would argue that some of the more advanced uses sacrifice readability and simplicity for not much gain in terms of reducing boilerplate.

Function Argument Destructuring

A common one I forget is available is destructuring of function arguments within the signature itself. I'll give you an example:

// This:
function talkToPets(shelter) {
	const {cats, dogs, birds} = shelter;
	// Or even more verbose, without destructuring at all
	//	const cats = shelter.cats
	//	const dogs = shelter.dogs
	//	const birds = shelter.birds
}

// Becomes this:
function talkToPets({cats, dogs, birds}) {
	//
}

You can even define defaults!

function talkToPets({cats = ['whiskers','felix'], dogs, birds}) {
	//
}

Computed Property Names

Computed property names are an awesome new(er) feature (ES6), which reduce a lot of the standard boilerplate involved when trying to use a dynamic value as the key itself on an object. For example, pretend you want to store an action keyed by a timestamp. Without computed property names, you would have to use:

const nowStamp = (new Date()).getTime();
const actions = {};
actions[nowStamp] = 'User logged in';

Using computed properties, you can use the variable directly as the key:

const nowStamp = (new Date()).getTime();
const actions = {[nowStamp]: 'User logged in'}

Or, even more succinct

const actions = {[(new Date()).getTime()]: 'User logged in'}

Computed Property Trick: Variable name as key

If you want to construct an object, where the keys are the actual variable names, and the values are the values, perhaps for logging, this is easy to do with Computer Properties, + ES6 Shorthand Property Names.

var dog = {
	name: 'barky',
	age: 5
}
var cat = {
	name: 'whiskers',
	age: 8
}
console.log({dog, cat});
/*
{dog: {…}, cat: {…}}
	dog: {name: "barky", age: 5}
	cat: {name: "whiskers", age: 8}
*/

For the above, console.table([dog,cat]) might be even better, since dog and cat share the same keys.

Buffers

String to buffer

In Node.js, this is pretty easy with built-ins:

const myBuff = Buffer.from(myString, 'utf8');

With Web APIs, there is a bit more setup (and the ecosystem is currently changing). Currently, the best way seems to be to use the TextEncoder API, which returns a buffer (specifically a Uint8Array):

const encoder = new TextEncoder();
const myBuff = encoder.encode(str);

Array methods

Why are these so hard to remember? I don't know. But hopefully these practical examples will help!

Here is a master table of methods, some of which will be broken down more further down the page. An even more complete list of methods can be found on MDN, here.

Method Use Signature
forEach Loop over an array and callback for each element myArr.forEach((element) => doAny(element) )

Full Signature:
myArr.forEach((element, index, myArr) => doAny(element))
map Create a new array from the output of a callback called on each element of the original const formattedArr = myArray.map((element) => return newElement)
filter Creates a new array from the elements of the source that passed a test. Key to remember: If you want to keep element, return true, if you want to discard, return false const filtered = myArr.filter((element) => true || false)

Full:
const filtered = myArr.filter((element, index, sourceArr) => true || false, thisArg?)
findIndex Find the index of the first element in the arr that passes your test function myArr.findIndex((element) => true || false)
push Add to end of array myArr.push(newElement)
unshift Add to start of array myArr.unshift(newElement)
pop Remove from end const removedEnd = myArr.pop()
shift Remove from start const removedStart = myArr.shift()
indexOf Get the index of thing const found = myArr.indexOf(searchVal)

Will be -1 if not found.
splice Remove by index const removed = myArr.splice(startIndex, deleteCount)

Does modify original array in place.

Elements can be inserted in place of those removed, by passing as final args.
slice Returns a copy of a subsection of the original array const mySlice = myArr.slice(startIndex, endIndex)

Does not modify original array

Element at endIndex is not included in extracted.

This is a great way to quickly create a clone of an array - use without arguments:
const clone = myArr.slice()
join Join elements of an array const joined = myArr.join(separator)
concat Join multiple arrays together const combined = myArr.concat(myArrBeta)
reverse Reverse the order myArr.reverse()
sort Sort the array myArr.sort((firstElem, secondElem) => (+ || - || same))

Also, see subsection below
reduce Reduces an array to a single element output myArr.reduce((runningValue, currentValue) => newRunningValue)

Also, see subsection below
some Tests that at least one element of array satisfies test const result = myArr.some(testFunc)

Full:
const result = myArr.some((elem,index,fullArr)=> true || false, thisArg?)

For each of the samples, this will be the raw starting array:

const users = [{
	"id": 25,
	"name": "Amata Pittet",
	"email": "apittet0@utexas.edu",
	"age": 32,
	"num_pets": 1,
	"notification_opt_out": false
}, {
	"id": 10,
	"name": "Tessi Maddy",
	"email": "tmaddy1@cocolog-nifty.com",
	"age": 29,
	"num_pets": 2,
	"notification_opt_out": true
}, {
	"id": 3,
	"name": "Gillan Birkby",
	"email": "gbirkby2@thetimes.co.uk",
	"age": 50,
	"num_pets": 0,
	"notification_opt_out": true
}];

Creating an Array

  • If the "thing" is iterable, or array-like, you can use Array.from()
  • For a regular object, you can use...

    • For values:

      • Object.values(object);
    • For keys:

      • Object.keys(object);
    • Both ({alpha: 1, beta: 2} => [{alpha: 1}, {beta: 2}])

      • Array.prototype.reduce is a decent approach:

        Object.keys(myObj).reduce((run, curr) => {
        	run.push({
        		[curr]: myObj[curr]
        	});
        	return run;
        }, []);
        
        // Or, one liner:
        Object.keys(myObj).reduce((run, curr) => [...run, { [curr]: myObj[curr] }], []);
      • Warning: I've used [curr]: value to set the key to the value of a variable. This is an ES6 feature, called "computed property names"; for legacy support, you need to first create an object, then create key-pair normally (tempObj = {}; tempObj[curr] = myObj[key]);

  • For creating an array from scratch, prefilled with a value:

    • Use const myArr = Array(n).fill(val)

      • Where n = size of array, and val is value to fill with
    • Relevant S/O

Array Splice vs Slice

If you are having trouble remembering the difference between splice and slice, an easy way to remember is imagining you want to buy a piece of cake. You would ask for a slice, and would definitely not use the word splice.

Similarly, if you want part of an array, you use slice, and calling myArray.slice() to clone the entire array is analogous to buying an entire cake but buying it piece by piece.

For splice, a good analogy is old movie film reel editing, where you cut scenes out of a film by removing a section and then joining the ends where the gap has opened up.

Array Reduce

MDN: Array.prototype.reduce

Signature:

  • Minimal: myArr.reduce((runningValue, currentValue) => newRunningValue)
  • Full: myArr.reduce((runningValue, currentValue, currIndex, sourceArr) => newRunningValue, initialValue)

What:

  • At its simplest, reduce takes an array and reduces it to *one* thing.

Uses:

  • Often used for summing:

    const totalPets = users.reduce((running, curr)=> curr.num_pets + running, 0)
    // > 3
    [0, 24, 20].reduce((run,curr) => run + curr) // 44
  • Map an array of objects to a dictionary object with sensible keys. In this example, the user's ID # will become the object key

    const usersById = users.reduce((running,curr) => {
    	running[curr.id] = curr;
    	return running;
    }, {});
    // Now we can do this:
    const gillian = usersById[3];
  • Creating aggregators:

    const averages = users.reduce((running, curr, index, srcArr) => {
    	const count = (index + 1);
    	const totalAge = ((running.totalAge || 0) + srcArr[index].age);
    	const totalPets = ((running.totalPets || 0) + srcArr[index].num_pets);
    	running['totalAge'] = totalAge;
    	running['totalPets'] = totalPets;
    	running['avgAge'] = totalAge / count;
    	running['avgPets'] = totalPets / count;
    	return running;
    }, {});
    
    delete averages.totalAge;
    delete averages.totalPets;
    
    console.log(averages)
    // > {avgAge: 37, avgPets: 1}

Note: MDN and most sites use "accumulator" as the name of the first argument to reduce. This bothers me, as besides being overly specific, it implies that reduce is about summing or gathering values together, which is does not have to be. I much prefer to use variables like runningValue, which just implies that there is a value carried while reducing and is used for the output.

Array Sort

MDN: array.prototype.sort

Signature:

  • myArr.sort((firstElem, secondElem) => ( - || + || 0))

What:

  • Sorts the array based on comparison function / callback

Here is how your comparison function should return a value:

Element you want to come first / move forwards What you should return
firstElem < 0 ( - )
Neither (don't change position) 0
secondElem > 0 ( + )

Put another way, if you are going to sort numerically, here is how you would apply subtraction to sort:

Sort Direction Basis of comparison
Small -> Large firstElem - secondElem
Large -> Small secondElem - firstElem

For example, if we wanted to sort our users by age, from youngest to oldest, we could do this:

const youngToOldUsers = users.sort((userA, userB) => userA.age - userB.age);

But you can use it with more than just numerical comparison!

For example, what if we want to sort users so that everyone that has opted out of notifications comes before those who have not:

const optedOutFirst = users.sort((userA,userB) => userA.notification_opt_out === true ? -1 : 0);

Loop Types

MDN main page: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration

Another resource - https://www.tutorialrepublic.com/javascript-tutorial/javascript-loops.php

Loop Signature Note
for for ([initialVal]; [executeIfCondition]; [finalExpression];) {...} Don't use const for variable assignment of initialVal - won't allow modification via ++, --, etc.

Prefer let or var
do...while do {[statement]} while ({condition}); Condition is evaluated after do block, and if true, starts another loop through
while while ([condition]) {[statement]} Condition is evaluated before statement is executed.

You can use break to exit statement early and stop loop.
for...in for ([variable] in [object]) {[statement]} Only iterates over enumerable properties, in a random order.

Unlike for loops, you can use const for assigment here (and probably should!).

Although works with arrays, not recommended due to random order.

In general, simple for, or for...of is recommended over for...in. Unless you need to iterate over object keys of course.
for...of for ([variable] of [iterableObject]) {[statement]} Loop over *iterable objects*.

Using let vs const depends on how you use var in statement - use let if reassigning / modifying.
[].forEach myArr.forEach((element) => doAny(element) )

Full Signature:
myArr.forEach((element, index, myArr) => doAny(element))
Loop over an array and callback for each element

For Loops - Which to Pick?

In general, for...of is recommended as the go-to pick.

Compared to for...in

  • It ignores non-iterable properties, for...in does not.

Compared to forEach

  • for...of works on many different iterable objects
  • for...of is also generally faster
  • for...of allows exiting the loop early (via break), whereas forEach does not

The main remaining reason to use for() or [].forEach() is if you need access to the index. But this could also be accomplished with a counter, and most of the time is not needed anyways.

Special Loop Flow Controls

See:


Console Methods

Method Use Signature
console.log Explodes your computer. JK! Logs to the console of course! console.log(thingToLog);

console.log(object_1, object_2?, object_3?, ...)

console.log(msgStr, substr_1?, substr_2?, ...) (string replacement)
console.assert Spit something out to the console only if your expression evaluates as falsy.

Kind of like wrapping logs in if statements -> if(!success) {console.log(result);} is close to console.assert(success, result)
console.assert(boolLikeAssertion,thingToLog);

console.assert(boolLikeAssertion, object_1, object_2?, object_3?, ...)

console.assert(boolLikeAssertion, msgStr, substr_1?, substr_2?, ...) (string replacement)
console.clear Clears the console console.clear()
console.count Increments and displays a counter value console.count(labelStr?)
console.countReset Resets the global counter, or a specific one if passed a label. console.countReset(labelStr?)
console.debug Logs at the debug level, which means it will only show for users with that level enabled. console.debug(thing)

Full signature matches console.log()
console.dir Displays a tree / interactive hierarchical display of an object, with collapsible sections.

Usually identical to just using log()
console.dir(myJsObj)
console.dirxml Same as console.dir() (shows hierarchical tree view), but for XML/HTML element.

Also usually identical to just using log()
console.dirxml(object)
'console.error' Logs error console.error(thing)

Full signature is same as log()
console.group Starts a group of messages in the console (kind of like a tree level) console.group()

console.group(label?)

Use console.groupCollapsed() if you want to start with it collapsed by default
console.groupEnd Ends a group of messages in the console (started by console.group()) console.groupEnd()
console.info Logs at the info level. Identical to log() except for Firefox, which displays an icon. console.info(thing)

Full signature matches console.log()
console.table Output a pretty formatted table, with auto headers and body.

Only helpful if all objects have same keys, logging a single object, or logging a multidimensional array where each sub-array has the same length
console.table([thing_1, thing_2, ...])

console.table([thing_1, thing_2, ...], [columnNameToOmit_1, ...])
console.time Start a timer, which can be checked later. console.timer(labelStr?)
console.timeEnd Stop a timer, and log the value. console.timeEnd(label?)
console.timeLog Log the value of a timer without stopping it console.timeLog(label?)
console.trace Output an (interactive) stack trace to the console. console.trace()

Or, pass any data (unlimited), and they will be logged just like console.log() --->
console.trace(any?)
console.warn Logs at the warn level. console.warn(thing)

Full signature is same as log()

arg_name? <-- ? indicates argument is optional


Post vs Pre-increment

Most of the conversation around post vs pre-incrementing is about optimization and performance; but this is a bit of a moot point in a more abstracted / less bare metal language like JS anyways. But... there is something very important to remember: preincrement adds one to the value and then returns it, whereas postincrement returns the value first and then increments it last.

Why does this matter? Consider the following example, where we have a value that is either a number or undefined, and if undefined, we want to start it at 1:

var val = undefined;
val = val ? val++ : 1;
// > 1
// Good so far!
val = val ? val++ : 1;
// > 1
// Wait... val is not going up!

Because we are assigning the value of the return of a postincrementer to itself, and a postincrementer always returns the original value before incrementing it, the value is stuck at whatever was first fed into the postincrementer!

Now, with pre-incrementer:

var val = undefined;
val = val ? ++val : 1;
// > 1
// Good so far!
val = val ? ++val : 1;
// > 2
// Yeahoo!

URL API

The URL Web API has been around for a while now, and provides a much-need abstraction API for dealing with URLs.

For example, to access a query string parameter with document.location.search requires some sort of pattern matching (e.g. RegEx) to extract the key pair you want, but with the URL API, it is as easy as (new URL(document.location)).searchParams.get(myParamKeyStr).

URL API Constructor

One of the main things to remember is that, in order to use the methods of URL(), you need to instantiate an instance of a URL object by calling the constructor.

The constructor can take:

  • A full URL - aka absolute URL

    • const myUrlObj = new URL('https://joshuatz.com/blog/?utm_source=cheatsheets')
  • A relative URL, plus a base

    • const myUrlObj = new URL('/blog/?utm_source=cheatsheets', 'https://joshuatz.com')
  • Something that can be stringified to one of the above options

    • This is helpful to know, because it lets you use shorthand; if you want to construct a URL object from the current browser URL, you can use new URL(document.location) instead of new URL(document.location.href), since document.location.toString() returns the full href value anyway.
Markdown Source Last Updated:
Thu Apr 16 2020 01:37:54 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Wed Aug 21 2019 00:46:11 GMT+0000 (Coordinated Universal Time)
© 2020 Joshua Tzucker, Built with Gatsby