MAD Study Hub

Home / MAD2 / Week 1

Week 1 · JavaScript basics: values, functions and the DOM

Official syllabus line: Basics of JavaScript
About 100 minQuiz 1 material (see exam radar)BSCS2006 (+ project BSCS2006P) · Thejesh G N, Nitin Chandrachoodan
Before you start: Basic HTML (tags, ids) and the idea of a variable from any programming language. Nothing about Vue yet.

The one-minute story

Think of it like this

JavaScript is the waiter in a restaurant. HTML is the menu (what exists), CSS is the decoration (how it looks), and JavaScript is the waiter who actually does things: takes your order when you click a button, brings a new dish without rebuilding the restaurant, and remembers what each table asked for.

The waiter is fast but has odd habits. Ask him to add the text "5" and the number 3 and he does not complain, he hands you "53". Ask him for a name he was never given and he says undefined instead of crashing. Most of this week is learning those habits (types, coercion, hoisting, this) so you can predict exactly what he will do. The exam is full of "predict the output" questions, and they are all about these habits.

By the end of this week you can:

  • explain where JavaScript runs and run it in the browser console and in Node;
  • predict the output of code using var, let, const, hoisting, == and ===;
  • write functions (declaration, expression, arrow) and use map, filter, reduce;
  • use objects, destructuring, the spread operator and JSON;
  • read and write a small DOM program with events.

Words you need

Words you need
  • JavaScript (JS) - the programming language of the web; runs in every browser and also outside it (Node).
  • Node.js - a program that runs JavaScript on your computer or server, without a browser.
  • Console - the place where console.log prints (browser dev tools, or the terminal in Node).
  • Scope - the region of code where a name is visible.
  • Hoisting - declarations are registered before the code runs, so some names exist "early".
  • Temporal dead zone (TDZ) - the stretch between the start of a block and the line of a let/const, where using the name is an error.
  • Type coercion - JavaScript silently converting a value to another type ("5" * 2 becomes 10).
  • Truthy / falsy - how a value behaves inside an if test.
  • Arrow function - short function syntax (x) => x * 2, with its own rules for this.
  • Callback - a function you hand to another function to be called later.
  • Destructuring - unpacking array items or object properties into variables.
  • JSON - a text format for data that looks like a JS object; JSON.stringify and JSON.parse convert.
  • DOM - the page as a tree of objects that JavaScript can read and change.

Idea 1: What JavaScript is and where it runs

JavaScript was created for the browser, but the language itself is just a language. Two places run it:

WhereWhat you getTypical use
Browserthe language plus document, window, fetch, localStorage, eventsmaking pages interactive; your Vue app
Node.jsthe language plus files, network servers, require/importtools, build steps (npm), servers

Both use an engine (Chrome and Node use V8) that reads your code and runs it. JavaScript is single-threaded: one thing at a time (week 2 shows how it still waits for the network without freezing).

Put JavaScript in a page with a script tag. It runs when the browser reaches it.

<!DOCTYPE html>
<html>
  <body>
    <h1 id="title">Hello</h1>
    <script src="app.js"></script>   <!-- put at the END of body, so the h1 exists -->
  </body>
</html>
// app.js
console.log("page loaded");              // goes to the browser console (F12)
document.getElementById("title").textContent = "Hi from JS";

console.log is your best friend: it prints any values, separated by spaces. Use console.log(a, b) to see two things at once. A script tag with type="module" (week 2) is deferred automatically; a normal one blocks the page while it loads, which is why it goes at the end of body (or gets the defer attribute).

Your turn: 1. Where does it run?

(a) Can document.getElementById run in Node? (b) Can console.log run in the browser? (c) Which runs a script file named tool.js from the terminal?

Need a hint?

Node has no page, so no document.

Show the full solution

(a) No, there is no page in Node (document is not defined). (b) Yes, it prints in the dev-tools console. (c) node tool.js.

Idea 2: Variables, scope and hoisting

Three ways to declare a variable:

varletconst
Scopefunction (ignores blocks)block { }block { }
Re-assignyesyesno
Re-declare in same scopeyeserrorerror
Hoistedyes, starts as undefinedyes, but in the TDZyes, but in the TDZ
The idea

Use const by default, let when the value must change, and avoid var. const stops re-assignment of the name; it does not freeze the object inside (you can still push into a const array).

{ var v = 1; let l = 2; }
console.log(v);          // 1       var leaks out of the block
console.log(typeof l);   // undefined  l is not visible here

console.log(a);          // undefined  (var is hoisted, value not yet set)
var a = 5;

try { console.log(b); } catch (e) { console.log(e.name); }   // ReferenceError (TDZ)
let b = 5;

const list = [1, 2];
list.push(3);            // allowed
console.log(list);       // [ 1, 2, 3 ]
try { list = []; } catch (e) { console.log(e.name); }        // TypeError

Hoisting in one sentence: before running, JavaScript scans for declarations. var x is created and set to undefined; a function declaration is created with its whole body; let/const are created but locked until their line (TDZ).

console.log(add(2, 3));      // 5   declaration hoisted with its body
function add(a, b) { return a + b; }

try { sub(5, 2); } catch (e) { console.log(e.name + ": " + e.message); }
var sub = function (a, b) { return a - b; };   // only `var sub` is hoisted (as undefined)
// prints: TypeError: sub is not a function

The most asked scope puzzle is var in a loop with a delayed callback:

for (var i = 0; i < 3; i++) setTimeout(() => console.log("var", i), 0);
for (let j = 0; j < 3; j++) setTimeout(() => console.log("let", j), 0);
// var 3, var 3, var 3, let 0, let 1, let 2

There is one i shared by all three callbacks, and it is 3 when the loop ends. let makes a fresh j for each round.

Watch out - real exam trap
  • typeof of an undeclared name is "undefined", but typeof of a let in its TDZ throws.
  • var inside if/for is visible outside it. let is not.
  • const obj = {}; obj.x = 1; is fine. obj = {} is the error.
  • Assigning to a name that was never declared (total = 5) quietly makes a global variable in sloppy mode. Do not.

Idea 3: Types, coercion and equality

There are seven primitive types and one object type:

TypeExampletypeof
number42, 3.14, NaN, Infinity"number"
string"hi", 'hi'"string"
booleantrue, false"boolean"
undefineda variable never given a value"undefined"
null"deliberately empty""object" (an old bug)
symbolSymbol("id") (a unique key)"symbol"
bigint12345678901234567890n"bigint"
object{}, [], functions, dates"object" (functions: "function")

There is one number type (no int/float split), and 0.1 + 0.2 is 0.30000000000000004.

console.log(typeof 5, typeof "5", typeof null, typeof undefined, typeof [], typeof NaN, typeof (() => 1));
// number string object undefined object number function
console.log(Array.isArray([]));   // true  (the right way to test for an array)

Coercion: + joins, everything else calculates

console.log("5" + 3);      // 53     one side is a string, so + joins
console.log("5" - 3);      // 2      - always means numbers
console.log("5" * "2");    // 10
console.log(true + 1);     // 2      true becomes 1
console.log(null + 1);     // 1      null becomes 0
console.log(undefined + 1);// NaN    undefined becomes NaN
console.log("abc" * 2);    // NaN    "not a number"
console.log(1 + 2 + "3");  // 33     left to right: 3, then "33"
console.log("1" + 2 + 3);  // 123
console.log(parseInt("42px"), Number("42px"), Number(""), parseInt(undefined));
// 42 NaN 0 NaN

== converts types, === does not. Always use === unless you know why.

console.log(0 == "", "0" == false, null == undefined);   // true true true
console.log(0 === "", null === undefined);               // false false
console.log(NaN == NaN, NaN === NaN, Number.isNaN(NaN)); // false false true
console.log([1] == 1, [] == false);                      // true true

Truthy and falsy

There are exactly eight falsy values: false, 0, -0, 0n, "", null, undefined, NaN. Everything else is truthy, including "0", "false", [] and {}.

console.log(Boolean([]), Boolean(""), Boolean("0"), !!{}, !!NaN);
// true false true true false
Watch out - real exam trap
  • typeof null is "object"; typeof NaN is "number"; typeof [] is "object".
  • "5" + 3 is "53" but "5" - 3 is 2.
  • NaN is not equal to itself. Test with Number.isNaN(x).
  • [] and {} are truthy; "0" is truthy; 0 is falsy.
  • parseInt("12abc") is 12 (reads digits until it fails); Number("12abc") is NaN.
Your turn: 2. Predict the output
console.log(1 + "2" + 3, 1 + 2 + "3", "10" / 2, "a" - 1, [] + [], typeof typeof 1);
Need a hint?

Go left to right. typeof always returns a string.

Show the full solution

"123", "33", 5, NaN, "" (empty string, two empty arrays become empty strings), "string". Printed: 123 33 5 NaN string (there is an empty string between the NaN and "string").

Idea 4: Operators, template literals, control flow and loops

  • Arithmetic: + - * / % ** (2 ** 3 is 8). Increments: i++, i += 2.
  • Compare: < > <= >= === !==.
  • Logic: &&, ||, !. They return one of the operands, not just true/false. || returns the first truthy operand (or the last), && returns the first falsy operand (or the last). The exam loves this.
  • ?? (nullish coalescing) falls back only for null or undefined: 0 ?? 5 is 0, but 0 || 5 is 5.
  • Ternary: cond ? a : b.
console.log(2 && 4, 0 && 2, 2 || 0, 0 || "", "" || "dflt");   // 4 0 2 "" dflt
console.log(0 || 5, 0 ?? 5, null ?? 5, undefined ?? "x");      // 5 0 5 x
const age = 17;
console.log(age >= 18 ? "adult" : "minor");                   // minor

Template literals use backticks, allow ${expression} and span lines:

const name = "Asha", n = 3;
console.log(`Hello ${name}, you have ${n * 2} items.`);   // Hello Asha, you have 6 items.

Control flow and loops

const marks = 72;
if (marks >= 90) console.log("A");
else if (marks >= 60) console.log("B");      // B
else console.log("C");

switch (marks > 50) {            // switch uses ===, and needs break
  case true: console.log("pass"); break;
  default: console.log("fail");
}

for (let i = 0; i < 3; i++) console.log(i);                  // 0 1 2
let k = 0; while (k < 2) { k++; }                            // k is 2
for (const x of ["a", "b"]) console.log(x);                  // a b      values
for (const key in { p: 1, q: 2 }) console.log(key);         // p q      keys (strings)
for (const idx in ["a", "b"]) console.log(idx, typeof idx);  // 0 string / 1 string
The idea

for...of walks the values of something iterable (array, string). for...in walks the keys (property names) of an object, always as strings. On an array for...in gives indexes as strings, so prefer for...of for arrays. break leaves the loop, continue skips to the next round.

Your turn: 3. FizzBuzz-lite

Print the numbers 1 to 15, but write "Fizz" for multiples of 3 and "Buzz" for multiples of 5 (and "FizzBuzz" for both).

Need a hint?

Test the "both" case first, using %.

Show the full solution
for (let i = 1; i <= 15; i++) {
  if (i % 15 === 0) console.log("FizzBuzz");
  else if (i % 3 === 0) console.log("Fizz");
  else if (i % 5 === 0) console.log("Buzz");
  else console.log(i);
}

It prints 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz.

Idea 5: Functions

Functions are values (first-class): you can store them in variables, pass them to other functions and return them.

function square(x) { return x * x; }          // declaration: hoisted
const cube = function (x) { return x ** 3; };   // expression: not usable before this line
const double = (x) => x * 2;                    // arrow, one expression: implicit return
const make = (a, b) => ({ sum: a + b });        // returning an object literal needs ( )
const greet = (who = "friend") => `Hi ${who}`;  // default parameter

console.log(square(3), cube(2), double(4), make(1, 2), greet(), greet("Ravi"));
// 9 8 8 { sum: 3 } Hi friend Hi Ravi
console.log((function () {})());                // undefined  no return means undefined
// first-class: pass a function, return a function
const apply = (f, v) => f(v);
console.log(apply(square, 5));       // 25
const adder = (n) => (x) => x + n;
console.log(adder(10)(5));           // 15
const nums = (...all) => all.length; // rest parameters collect the extras
console.log(nums(1, 2, 3));          // 3

this: a first look

Inside a normal function, this means "the object before the dot at the call site". An arrow function has no this of its own: it uses the this of the code around it. Week 2 gives the full rules (call, bind, apply).

const user = { nick: "Asha", hi() { return "Hi " + this.nick; } };
console.log(user.hi());      // Hi Asha      object before the dot is user
const detached = user.hi;
try { console.log(detached()); } catch (e) { console.log("lost this"); }
// Hi undefined (sloppy script) or "lost this" (strict mode/module): the dot is gone
Watch out - real exam trap
  • A function declaration works before its line; a function expression (even const f = () => {}) does not.
  • x => { value } with braces needs an explicit return; x => value returns it implicitly.
  • (x) => ({ a: x }): parentheses so the braces are an object, not a function body.
  • Extracting a method (const f = obj.method) loses this.
Your turn: 4. Rewrite

Rewrite as an arrow function: function area(w, h = 1) { return w * h; }. What do area(3) and area(3, 4) give?

Need a hint?

Parameters stay the same, body becomes an expression.

Show the full solution

const area = (w, h = 1) => w * h; gives 3 and 12.

Idea 6: Arrays and their methods

const a = [10, 20, 30];
console.log(a.push(40), a);    // 4 [ 10, 20, 30, 40 ]   push returns the NEW LENGTH
console.log(a.pop(), a);       // 40 [ 10, 20, 30 ]      pop returns the removed item
console.log(a.length, a[0], a[5]);   // 3 10 undefined
console.log(a.slice(1, 3), a);       // [ 20, 30 ] [ 10, 20, 30 ]   slice COPIES, original unchanged
console.log(a.splice(1, 1), a);      // [ 20 ] [ 10, 30 ]           splice CHANGES the original
const b = [...a, 99];                // spread: copy into a new array
console.log(b, [..."hi"]);           // [ 10, 30, 99 ] [ 'h', 'i' ]

The "big four" take a callback and do not change the original array:

MethodReturnsCallback does
map(f)new array, same lengthtransform each item
filter(f)new array, shorterkeep items where f is truthy
reduce(f, start)one valuecombine: f(accumulator, item)
forEach(f)undefinedjust do something per item
find(f)first matching item, or undefined
const n = [1, 2, 3, 4, 5];
console.log(n.map(x => x * 2));                  // [ 2, 4, 6, 8, 10 ]
console.log(n.filter(x => x % 2 === 1));         // [ 1, 3, 5 ]
console.log(n.reduce((acc, x) => acc + x, 0));   // 15
console.log(n.find(x => x > 3), n.find(x => x > 9));   // 4 undefined
console.log(n.indexOf(3), n.includes(7));        // 2 false
console.log(n.forEach(x => x));                  // undefined
console.log([10, 9, 1].sort());                  // [ 1, 10, 9 ]  default sort compares AS TEXT
console.log([10, 9, 1].sort((p, q) => p - q));   // [ 1, 9, 10 ]
console.log(["1", "2", "3"].map(parseInt));      // [ 1, NaN, NaN ]  map also passes the index!
Solved example: 1. A real exam chain
const data = [
  { name: "Alpha", score: 40 }, { name: "Beta", score: 30 },
  { name: "Charlie", score: 50 }, { name: "Delta" },
];
const total = data
  .map(p => parseInt(p.score) || 0)
  .filter(score => score >= 40)
  .reduce((acc, score) => acc + score, 0);
console.log("Total Score:", total);

Step by step: map turns each score into a number: 40, 30, 50, and for Delta parseInt(undefined) is NaN, which is falsy, so NaN || 0 is 0: [40, 30, 50, 0]. filter keeps >= 40: [40, 50]. reduce adds from 0: 90. Output: Total Score: 90.

Watch out - real exam trap
  • push returns the length, pop returns the item, forEach returns undefined, splice mutates, slice does not.
  • Arrays are objects: b = a copies the reference; b = [...a] copies the items (a shallow copy).
  • ["1","2","3"].map(parseInt) is [1, NaN, NaN]. sort() without a function sorts as strings.
Your turn: 5. Chain it

[3, 8, 1, 9]: keep numbers above 2, double them, then add them up.

Need a hint?

filter, then map, then reduce.

Show the full solution

[3,8,1,9].filter(x => x > 2).map(x => x * 2).reduce((a, x) => a + x, 0): filter gives [3,8,9], map [6,16,18], reduce 40.

Idea 7: Objects, destructuring and JSON

An object is a bag of key: value pairs. A function stored as a value is a method.

const person = { name: "Asha", age: 20, skills: ["js", "py"], greet() { return "Hi " + this.name; } };
console.log(person.name, person["age"], person.greet());   // Asha 20 Hi Asha
person.city = "Chennai"; delete person.age;               // add, delete
console.log("city" in person, person.age, person.zip);      // true undefined undefined
console.log(Object.keys({ a: 1, b: 2 }), Object.entries({ a: 1 }));
// [ 'a', 'b' ] [ [ 'a', 1 ] ]

Destructuring and spread are everywhere in Vue code:

const [first, , third = 0] = [1, 2];          // positions; third gets its default
const { name, skills: [s1] } = person;        // names must match; nested allowed
console.log(first, third, name, s1);          // 1 0 Asha js

const base = { x: 1, y: 2 };
const copy = { ...base, y: 20, z: 3 };        // copy, later keys win
console.log(copy, base);                      // { x: 1, y: 20, z: 3 } { x: 1, y: 2 }
const extra = { ...(false && { secret: 1 }) };    // spreading false adds nothing
console.log(extra);                           // {}
Solved example: 2. Conditional spread (a past-paper pattern)
function isValidAge(age) { return !(age > 18); }
const validAgeParams = { voter_id: 123, constituency: "New Delhi" };
let some_value;                      // undefined
console.log(isValidAge(some_value) ? { name: "ABC", ...(!isValidAge(19) && validAgeParams) }
                                   : { name: "XYZ" });

undefined > 18 is false, so isValidAge(undefined) is true: take the first branch. isValidAge(19) is !(true) = false, so !isValidAge(19) is true, and true && validAgeParams is validAgeParams, which is spread in. Output: { name: 'ABC', voter_id: 123, constituency: 'New Delhi' }.

JSON

JSON is text. Keys and strings need double quotes; no functions, no comments, no trailing commas.

const text = JSON.stringify({ a: 1, b: undefined, c: () => 1, d: [1, undefined], e: "hi" });
console.log(text);                         // {"a":1,"d":[1,null],"e":"hi"}
const back = JSON.parse('{"id":7,"tags":["x","y"]}');
console.log(back.id, back.tags[1]);        // 7 y

stringify drops undefined and function values in objects (and turns them into null inside arrays). Browser storage and fetch bodies are text, so you will convert with these two calls all the time.

Your turn: 6. Destructure

const {a, b: {c}} = {a: 1, b: {c: 2, d: 3}}; What are a and c? Is b defined?

Need a hint?

Only names written on the left become variables.

Show the full solution

a is 1, c is 2. b is not defined (it is only a path to reach c), and neither is d.

Idea 8: The DOM and events

The browser turns your HTML into a tree of objects called the DOM. document is the root. JavaScript finds elements, reads or changes them, and reacts to events (click, input, submit, keydown).

// browser only
const out = document.querySelector("#out");          // first match of a CSS selector
const all = document.querySelectorAll(".item");      // list of every match
out.textContent = "changed";                         // set text (safe)
out.style.color = "red";
out.classList.add("big");
document.querySelector("button").addEventListener("click", () => { out.textContent = "clicked"; });

input.value is always a string, even for type="number", so convert before calculating. That is the classic calculator bug.

Solved example: 3. A tiny calculator
<input id="a" type="number"> <select id="op"><option>+</option><option>-</option>
<option>*</option><option>/</option></select> <input id="b" type="number">
<button id="go">=</button> <span id="out"></span>
<script src="calc.js"></script>
// calc.js
function calculate(a, op, b) {
  switch (op) {
    case "+": return a + b;
    case "-": return a - b;
    case "*": return a * b;
    case "/": return b === 0 ? "cannot divide by 0" : a / b;
    default: return "?";
  }
}
document.querySelector("#go").addEventListener("click", () => {
  const a = Number(document.querySelector("#a").value);   // value is a string: convert!
  const b = Number(document.querySelector("#b").value);
  const op = document.querySelector("#op").value;
  document.querySelector("#out").textContent = calculate(a, op, b);
});

The pure function calculate can be tested in Node: calculate(6, "*", 7) is 42. Without Number(...) the plus would join text: "2" + "3" is "23". Frameworks like Vue (later weeks) remove this manual querySelector plumbing by tying page and data together.

In your project

Examiners ask "what is the difference between let and var" and "why ===" even in a Vue project viva. Keep const/let only in your code and use === everywhere, so you can say it is a deliberate habit.

Exam radar

Exam radar

The keyword scan for this week matches about 423 distinct graded questions (about 570 of 848 in Quiz 1, 320 of 608 in Quiz 2 and 623 of 1471 in the End Term, by keyword, so approximate). Honest caution: "JavaScript" words appear in nearly every code question, and a large share of them are Vue questions whose answer is still decided by plain JavaScript rules. Pure-JavaScript "predict the output" questions mostly come in Quiz 2 and the End Term and test:

  • Array chains with map/filter/reduce and parseInt(...) || 0 (the score-total question above).
  • Operators returning operands (2 && 4, 2 || 0, 0 && 2).
  • Object spread with && to add keys conditionally.
  • this with call and arrow functions (week 2) and var becoming a global.
  • Storage values being strings ("10" + 5), covered in week 3.

Typical questions: "what is logged?", "which statement about let/const is false?", "what does x.sort() return for numbers?".

Watch out - real exam trap
  • Strings: + joins and * calculates. A value read from input or storage is a string.
  • &&/|| return an operand; ?? ignores 0 and "".
  • parseInt(""), parseInt(undefined) are NaN, and NaN || 0 is 0.
  • forEach returns undefined; map returns an array.

Quick quiz

Quick quiz

What does this print? console.log("5" + 3, "5" - 3)

  • 8 2
  • 53 53
  • 53 2
  • 8 8
+ with a string joins text ("53"); - always does arithmetic (2).

What is the output? console.log(2 && 4, 0 || 7, 0 ?? 7)

  • 2 7 7
  • 4 7 0
  • true true true
  • 4 0 7
&& returns 4 (last truthy), || skips the falsy 0 and returns 7, ?? keeps 0 because it is not null/undefined.

What is logged? for (var i = 0; i < 3; i++) setTimeout(() => console.log(i), 0)

  • 0 1 2
  • 3 3 3
  • 2 2 2
  • Nothing
There is only one var i, and the loop ends with i = 3 before any callback runs. With let it would be 0 1 2.

Select all TRUE statements. (select all that apply)

  • typeof null is "object".
  • const arr = []; arr.push(1) is allowed.
  • NaN === NaN is true.
  • let variables are function scoped.
NaN is never equal to itself, and let is block scoped.

[10, 9, 1].sort() returns...

  • [1, 9, 10]
  • [1, 10, 9]
  • [10, 9, 1]
  • an error
The default sort compares items as text, so "10" comes before "9".

Which statement about slice and splice is correct?

  • slice returns a copy and leaves the array unchanged; splice changes the array.
  • Both change the array.
  • slice changes the array; splice does not.
  • Both return a new array and leave the original unchanged.
splice removes/inserts in place; slice only copies a part.

Viva: say it out loud

Viva: say it out loud
What is the difference between var, let and const?

var is function scoped and hoisted as undefined; let and const are block scoped and sit in the temporal dead zone until their line. const cannot be re-assigned, but an object held in a const can still be changed. I use const by default and let only when needed.

What is hoisting?

Before the code runs, JavaScript registers the declarations. A function declaration is available with its body, a var exists as undefined, and let/const exist but cannot be used before their line.

Why prefer === over ==?

== converts types first, so 0 == "" and "0" == false are true, which hides bugs. === compares type and value with no conversion.

What is a callback and where did you use one?

A callback is a function passed to another function, to be called later. Examples are array.map(fn) and an event handler passed to addEventListener.

What is the difference between map, filter and reduce?

map makes a new array of the same length by transforming each item, filter keeps only items that pass a test, and reduce folds the whole array into one value. None of them changes the original array.

What is JSON and how do you use it in JavaScript?

JSON is a text format for data. JSON.stringify turns an object into text (for fetch bodies or storage), and JSON.parse turns text back into an object.

What is the DOM?

It is the page represented as a tree of objects. JavaScript reads and changes it with querySelector, textContent and addEventListener.

Recap

Remember this
  • JS runs in the browser (with document, fetch, storage) and in Node (with files and servers); it is single-threaded.
  • const by default, let if it changes, no var. var ignores blocks; let/const have a TDZ; function declarations hoist whole.
  • + joins when a string is involved; other operators convert to numbers. Use ===. Eight falsy values; [] and {} are truthy.
  • &&/|| return operands; ?? only skips null/undefined.
  • Functions are values. Arrow functions are short and take this from outside.
  • map/filter/reduce return new values; push/pop/splice change the array; forEach returns undefined.
  • Spread ... copies; destructuring unpacks; JSON is text.
  • input.value is a string; convert before calculating.
Code and facts to keep
  • typeof null -> "object"; typeof NaN -> "number"; Array.isArray(x)
  • Falsy: false 0 -0 0n "" null undefined NaN
  • "5" + 3 -> "53"; "5" - 3 -> 2; 1 + 2 + "3" -> "33"
  • for (const v of arr) values; for (const k in obj) keys (strings)
  • arr.reduce((acc, x) => acc + x, 0); arr.map(f); arr.filter(f)
  • const { a, b: { c } } = obj; const [x, y] = arr; { ...obj, k: v } [...arr, v]
  • JSON.stringify(obj) / JSON.parse(text)
  • document.querySelector("#id"), el.addEventListener("click", fn), el.textContent
Connected weeks (learn them together)

Practise with real exam questions

These come straight from past papers (with the real figures and the official answer key). Open 60 real questions on this week   All Quiz 1 papers