Skip to main content

Chapter 7 - Dictionaries and Structuring Data (JavaScript)

Here's a JavaScript-flavoured version of the same concepts, with small JS examples for each idea.


Objects (the dictionary equivalent)​

JavaScript uses plain objects for key-value pairs, written with {}. Keys are strings (or Symbols), and values can be anything.

Example:

const myCat = { size: "fat", color: "gray", age: 17 };
console.log(myCat.size); // 'fat'
console.log("My cat has " + myCat.color + " fur."); // My cat has gray fur.

Numeric keys are allowed but are converted to strings:

const spam = { 12345: "Luggage Combination", 42: "The Answer" };
console.log(spam[12345]); // 'Luggage Combination'

Objects vs arrays and ordering​

Arrays are ordered sequences indexed by integers; objects are key-value mappings, and key order doesn't affect deep equality (though you need a helper to compare).

Example:

const spam = ["cats", "dogs", "moose"];
const bacon = ["dogs", "moose", "cats"];
console.log(JSON.stringify(spam) === JSON.stringify(bacon)); // false

const eggs = { name: "Zophie", species: "cat", age: "8" };
const ham = { species: "cat", age: "8", name: "Zophie" };
console.log(JSON.stringify(eggs) === JSON.stringify(ham)); // false (key order differs)
// But they have the same content — use a deep-equal library for true comparison

Accessing a missing key returns undefined (no error thrown):

const spam2 = { name: "Zophie", age: 7 };
console.log(spam2.color); // undefined

Small project: birthday dictionary​

You can use an object to map names to birthdays and look them up interactively.

Example (Node.js with readline):

const readline = require("readline");
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });

const birthdays = { Alice: "Apr 1", Bob: "Dec 12", Carol: "Mar 4" };

function ask() {
rl.question("Enter a name: (blank to quit)\n>", (name) => {
if (name === "") return rl.close();
if (name in birthdays) {
console.log(birthdays[name] + " is the birthday of " + name);
} else {
console.log("I do not have birthday information for " + name);
rl.question("What is their birthday?\n>", (bday) => {
birthdays[name] = bday;
console.log("Birthday database updated.");
ask();
});
return;
}
ask();
});
}

ask();

Object.keys(), Object.values(), Object.entries()​

Object.keys(), Object.values(), and Object.entries() return arrays of keys, values, or key-value pairs, useful in loops and membership checks.

Example:

const spam = { color: "red", age: 42 };

for (const v of Object.values(spam)) {
console.log(v); // red then 42
}

for (const k of Object.keys(spam)) {
console.log(k); // color then age
}

for (const [k, v] of Object.entries(spam)) {
console.log("Key:", k, "Value:", v);
}

Converting to a real array:

Object.keys(spam);    // ['color', 'age']

Checking membership:

"color" in spam;                            // true
Object.values(spam).includes("red"); // true

Default values (like get())​

Use ?? (nullish coalescing) for defaults when a key might not exist, avoiding undefined.

Example:

const picnicItems = { apples: 5, cups: 2 };
console.log("I am bringing " + (picnicItems.cups ?? 0) + " cups.");
console.log("I am bringing " + (picnicItems.eggs ?? 0) + " eggs.");

Without ??, picnicItems.eggs would be undefined.


Setting defaults (like setdefault())​

Use ??= (logical nullish assignment) to set a key only if it is missing or null/undefined.

Example:

const spam = { name: "Pooka", age: 5 };
spam.color ??= "black";
console.log(spam); // { name: 'Pooka', age: 5, color: 'black' }

spam.color ??= "white";
console.log(spam.color); // still 'black'

Character frequency counter​

You can combine ??= with a loop to count occurrences of each character in a string.

Example:

const message = "It was a bright cold day in April, and the clocks were striking thirteen.";
const count = {};

for (const character of message) {
count[character] ??= 0;
count[character] = count[character] + 1;
}

console.log(count); // object mapping each char to its count

Modeling real-world things: chessboard object​

You can model a chessboard with an object whose keys are squares like 'a1'–'h8' and values are two-character piece codes like 'wK', 'bQ'.

Example board fragment:

const board = {
h1: "bK",
c6: "wQ",
g2: "bB",
h5: "bQ",
e3: "wK",
};

Missing keys represent empty squares.


Chessboard: starting position and template​

A constant object holds the initial piece layout, and a template string with placeholders is used to print the board.

Tiny sketch of the idea:

const STARTING_PIECES = {
a8: "bR", b8: "bN",
a1: "wR", b1: "wN",
// ... all 32 pieces
};

const WHITE_SQUARE = "||";
const BLACK_SQUARE = " ";

printChessboard(board) function​

printChessboard builds a 64-element array of strings (pieces or blanks) by looping over ranks and files, then formats them into the template.

Core idea:

function printChessboard(board) {
const squares = [];
let isWhiteSquare = true;
for (const y of "87654321") {
for (const x of "abcdefgh") {
const coord = x + y;
if (coord in board) {
squares.push(board[coord]);
} else {
squares.push(isWhiteSquare ? WHITE_SQUARE : BLACK_SQUARE);
}
isWhiteSquare = !isWhiteSquare;
}
isWhiteSquare = !isWhiteSquare;
}
// Format squares into the board template string
console.log(BOARD_TEMPLATE.replace(/{(\d+)}/g, (_, i) => squares[i]));
}

Interactive chessboard commands​

The main loop keeps a mainBoard object and responds to text commands (move, remove, set, reset, clear, fill, quit) by updating the object.

Examples of command handling:

let mainBoard = { ...STARTING_PIECES };

if (response[0] === "move") { // move e2 e4
mainBoard[response[2]] = mainBoard[response[1]];
delete mainBoard[response[1]];

} else if (response[0] === "remove") { // remove e2
delete mainBoard[response[1]];

} else if (response[0] === "set") { // set e2 wP
mainBoard[response[1]] = response[2];

} else if (response[0] === "reset") {
mainBoard = { ...STARTING_PIECES };

} else if (response[0] === "clear") {
mainBoard = {};
}

The spread { ...STARTING_PIECES } creates a shallow copy (like Python's copy.copy).


Nested objects and arrays​

You can nest objects inside objects (and mix with arrays) to represent richer structures, like guests and the items they bring to a picnic.

Example data and function:

const allGuests = {
Alice: { apples: 5, pretzels: 12 },
Bob: { "ham sandwiches": 3, apples: 2 },
Carol: { cups: 3, "apple pies": 1 },
};

function totalBrought(guests, item) {
let numBrought = 0;
for (const [k, v] of Object.entries(guests)) {
numBrought = numBrought + (v[item] ?? 0);
}
return numBrought;
}

console.log("Apples", totalBrought(allGuests, "apples")); // 7
console.log("Cups", totalBrought(allGuests, "cups")); // 3

Overall idea of the chapter​

The chapter's main message is: JavaScript objects work like Python dictionaries, letting you organize data with meaningful keys. The syntax differs (dot notation, ??, Object.keys()), but the core concept of key-value storage and nesting is the same. You can model real-world state like chessboards or inventories in a structured, scalable way.