This chapter is a condensed reference for the JavaScript language and its runtime environment. It is organized for lookup, not for reading. Each table covers one topic, and each entry is a fact that has a precise answer. The entries are drawn from the ECMAScript specification, the MDN documentation, and the behaviors that are verified by running the code. Where a behavior is version-dependent or runtime-dependent, the table says so explicitly.
Key point: JavaScript’s quirks are not random. They follow from the specification, and the specification is consistent. The == operator coerces, the this binding depends on the call site, and the event loop processes microtasks before macrotasks. Knowing the rule is faster than memorizing the exception.
Types and Coercion
Expression
Result
Reason
typeof null
"object"
Historical bug, preserved for compatibility
typeof undefined
"undefined"
—
typeof function(){}
"function"
Functions are callable objects
typeof []
"object"
Arrays are objects
typeof NaN
"number"
NaN is a numeric value
null == undefined
true
Loose equality treats them as equal
null === undefined
false
Different types
NaN === NaN
false
NaN is not equal to anything
Object.is(NaN, NaN)
true
SameValue algorithm
[] + []
""
Both convert to empty string
[] + {}
"[object Object]"
Array to string + object to string
{} + []
0 (as statement)
Block + unary plus on empty array
"5" - 2
3
Subtraction coerces to number
"5" + 2
"52"
Addition with string is concatenation
Falsy Values
Value
Falsy
false
Yes
0, -0, 0n
Yes
""
Yes
null
Yes
undefined
Yes
NaN
Yes
[], {}, "0", "false"
No
Variables and Scope
Keyword
Scope
Hoisted
TDZ
Reassignable
var
Function
Yes (initialized undefined)
No
Yes
let
Block
Yes (uninitialized)
Yes
Yes
const
Block
Yes (uninitialized)
Yes
No
Concept
Behavior
TDZ
Accessing a let/const before declaration throws ReferenceError
Hoisting
var declarations move to top; function declarations are fully hoisted
Block scope
{} creates a new scope for let/const
Closure
Function retains access to its lexical scope after the outer function returns
Functions and this
Call Site
this Value
obj.method()
obj
fn() (strict mode)
undefined
fn() (sloppy mode)
global object
new Fn()
new instance
fn.call(x)
x
fn.apply(x, args)
x
Arrow function
Lexical this (from enclosing scope)
Event handler
Element that fired the event (non-arrow)
Function Type
Hoisted
this
arguments
new
Function declaration
Yes
Dynamic
Yes
Yes
Function expression
No
Dynamic
Yes
Yes
Arrow function
No
Lexical
No
No
Method shorthand
No
Dynamic
Yes
No
Arrays
Method
Mutates
Returns
Use
push
Yes
New length
Add to end
pop
Yes
Removed element
Remove from end
shift
Yes
Removed element
Remove from start
unshift
Yes
New length
Add to start
splice
Yes
Removed elements
Add/remove anywhere
slice
No
New array
Copy portion
concat
No
New array
Merge arrays
map
No
New array
Transform
filter
No
New array
Subset
reduce
No
Accumulator
Aggregate
find
No
Element or undefined
First match
findIndex
No
Index or -1
Index of first match
includes
No
Boolean
Membership
sort
Yes
Same array
Sort in place
reverse
Yes
Same array
Reverse in place
// sort is lexicographic by default
[10, 9, 1].sort(); // [1, 10, 9]
[10, 9, 1].sort((a, b) => a - b); // [1, 9, 10]
Objects
Operation
Syntax
Property access
obj.key or obj['key']
Optional chaining
obj?.key?.nested
Nullish coalescing
obj.key ?? 'default'
Destructuring
const { a, b: renamed } = obj
Spread
{ ...obj, extra: 1 }
Shallow copy
{ ...obj } or Object.assign({}, obj)
Deep copy
structuredClone(obj)
Keys
Object.keys(obj)
Values
Object.values(obj)
Entries
Object.entries(obj)
Freeze
Object.freeze(obj)
Check property
'key' in obj or obj.hasOwnProperty('key')
Promises and Async
Concept
Behavior
Promise.resolve(x)
Promise fulfilled with x
Promise.reject(e)
Promise rejected with e
Promise.all([...])
Resolves when all resolve; rejects on first rejection
Promise.allSettled([...])
Resolves when all settle; never rejects
Promise.race([...])
Settles with the first settled promise
Promise.any([...])
Resolves on first fulfillment; rejects if all reject
async function
Always returns a Promise
await
Suspends until the promise settles
Unhandled rejection
Logged by the runtime; may terminate Node.js
// Promise.all: fails fast
await Promise.all([fetch(a), fetch(b)]); // rejects if either fails
// Promise.allSettled: never rejects
const results = await Promise.allSettled([fetch(a), fetch(b)]);
// [{ status: 'fulfilled', value }, { status: 'rejected', reason }]
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');
// Output: A, D, C, B
Iteration
Construct
Use
for
General loop
for...of
Iterable values (arrays, strings, Maps, Sets)
for...in
Enumerable property names (including inherited)
forEach
Array iteration; no break
map/filter/reduce
Functional transforms
Array.from(iterable)
Convert iterable to array
[...iterable]
Spread iterable into array
// for...of does not work on plain objects
for (const value of [1, 2, 3]) { } // ✅
for (const value of { a: 1, b: 2 }) { } // ❌ not iterable
for (const key in { a: 1, b: 2 }) { } // ✅ "a", "b"
┌──────────────────────────────────────────────────────────────┐
│ CALL SITE DETERMINES this │
│ │
│ obj.method() → obj │
│ fn() → undefined (strict) or global (sloppy) │
│ new Fn() → new instance │
│ fn.call(x) → x │
│ () => this → lexical this from enclosing scope │
│ │
│ Arrow functions do not have their own this. │
│ │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ Promise.all All resolve → resolve │
│ Any reject → reject │
│ │
│ Promise.allSettled All settle → resolve │
│ Never rejects │
│ │
│ Promise.race First settle → settle │
│ (resolve or reject) │
│ │
│ Promise.any First resolve → resolve │
│ All reject → AggregateError │
│ │
└──────────────────────────────────────────────────────────────┘
Module Loading
┌──────────────────────────────────────────────────────────────┐
│ ESM COMMONJS │
│ │
│ import x from 'mod' const x = require('mod') │
│ export default x module.exports = x │
│ export const y = 1 exports.y = 1 │
│ │
│ Static, async Dynamic, sync │
│ Live bindings Copied values │
│ Top-level await allowed No top-level await │
│ │
│ ESM is the standard. CommonJS is legacy but still common. │
│ │
└──────────────────────────────────────────────────────────────┘
Summary
Topic
Core Fact
typeof null
"object" (historical bug)
NaN equality
Not equal to itself; use Number.isNaN
== vs ===
== coerces; === does not
Falsy values
false, 0, -0, 0n, "", null, undefined, NaN
var vs let vs const
Function vs block scope; TDZ for let/const
this
Determined by call site; lexical for arrows
Array sort
Lexicographic by default; pass comparator
Promise.all
Fails fast on first rejection
Event loop
Microtasks before macrotasks
ESM vs CJS
Static/async vs dynamic/sync
Key takeaways:
typeof null returns "object". This is a bug from the first version of JavaScript that was never fixed because fixing it would break existing code. Checking for null requires value === null, not typeof .
NaN is not equal to itself.NaN === NaN is false. Use Number.isNaN(value) or Object.is(value, NaN) to test for NaN. The global isNaN coerces its argument, which produces surprising results for non-numeric values.
== coerces, === does not. The loose equality operator applies the abstract equality algorithm, which converts types before comparing. The strict equality operator compares both type and value. The only common use for == is x == null, which is true for both null and undefined.
this depends on the call site. The same function can have different this values depending on how it is called. Arrow functions are the exception: they capture this from the enclosing scope and cannot be rebound.
Microtasks run before macrotasks. Promises, queueMicrotask, and MutationObserver are microtasks. setTimeout, setInterval, I/O, and UI events are macrotasks. The event loop drains the microtask queue completely after each macrotask and after each synchronous execution.
Promise.all fails fast; Promise.allSettled never rejects. Use Promise.all when any failure should abort the operation. Use Promise.allSettled when every result is needed regardless of individual failures. Use Promise.any when the first success is sufficient.
Remember: JavaScript’s behavior is defined by the specification, and the specification is consistent even when the behavior looks arbitrary. The coercion rules, the this binding rules, the event loop ordering, and the module semantics all follow from a small number of principles. The cheatsheet is a lookup table for the facts, but the facts are connected. typeof null is a bug, but it is a bug that the specification preserves. this is dynamic, but it is dynamic in a predictable way. The event loop has two queues, and the order between them is fixed. Knowing the rule is faster than memorizing the exception.
Was this helpful?
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for: ✅ Finance (Mortgage, Interest, Inflation) ✅ Tech (Base64, JSON, Dev Suite, IP) ✅ Health (BMI, BMR, TDEE) ✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private 🔒 No data leaves your device 💎 100% Free