JavaScript Basics #5 Objects and Arrays

After #4 Functions showed tools for grouping behavior, it’s time for tools for grouping data: JavaScript’s two core data structures — objects and arrays.

Objects — collections of key-value pairs #

object basics
const user = {
  id: 'u1',
  name: 'Curtis',
  age: 30,
  isAdmin: false,
};

console.log(user.name);     // Curtis
console.log(user['name']);  // Curtis — same effect

Objects are a data structure that groups key-value pairs. Keys are strings (or symbols); values are any type.

Add/modify/delete properties #

modifying objects
const user = { id: 'u1', name: 'Curtis' };

user.age = 30;          // add
user.name = 'another name';  // modify
delete user.id;          // delete

console.log(user);
// { name: 'another name', age: 30 }

That an object’s contents change despite const is confusing at first. const means the variable can’t point somewhere else — not that the object’s contents can’t change (#2 reference vs primitive).

Shorthand notation #

You can use shorthand when the variable name matches the key.

property shorthand
const id = 'u1';
const name = 'Curtis';

// full
const user = { id: id, name: name };

// shorthand — once when variable name and key match
const userShort = { id, name };

This has been the standard since ES2015 — only older code uses the full form.

Method shorthand #

There’s also shorthand for functions as values.

method shorthand
const calc = {
  add(a, b) { return a + b; },          // shorthand
  subtract: function(a, b) { return a - b; },  // full
};

calc.add(2, 3);        // 5
calc.subtract(5, 2);   // 3

Arrays — ordered collections #

array basics
const fruits = ['apple', 'banana', 'grape'];

console.log(fruits[0]);       // apple — index starts at 0
console.log(fruits.length);   // 3
console.log(fruits[10]);      // undefined — missing index

An array is a kind of object too (typeof [] is 'object'). It’s specialized for handling ordered data via indices.

Add/remove #

modifying arrays
const fruits = ['apple'];

fruits.push('banana');     // append at end
// ['apple', 'banana']

fruits.unshift('grape');    // prepend at front
// ['grape', 'apple', 'banana']

fruits.pop();              // remove from end
// ['grape', 'apple']

fruits.shift();            // remove from front
// ['apple']

These four methods mutate the original. To leave the original alone and make a new array, spread (covered later) is safer.

Common array methods — map, filter, reduce #

Three methods that iterate while transforming/filtering/accumulating. The most-used tools in modern JavaScript.

map — transform #

map — transform every element
const nums = [1, 2, 3, 4, 5];

const doubled = nums.map((n) => n * 2);
// [2, 4, 6, 8, 10]

const labels = nums.map((n) => `#${n}`);
// ['#1', '#2', '#3', '#4', '#5']

Leaves the original alone and returns a new array. Same length; each element is the callback’s return value.

filter — filter #

filter — keep only matching
const nums = [1, 2, 3, 4, 5];

const evens = nums.filter((n) => n % 2 === 0);
// [2, 4]

const big = nums.filter((n) => n > 3);
// [4, 5]

Keeps elements for which the callback returns truthy. Length can shrink.

reduce — accumulate #

reduce — collapse to a single value
const nums = [1, 2, 3, 4, 5];

const sum = nums.reduce((acc, n) => acc + n, 0);
// 15

const max = nums.reduce((acc, n) => n > acc ? n : acc, -Infinity);
// 5

The second argument (0, -Infinity) is the initial value. Starting from it, the callback is applied element by element to build up the result. It’s the most powerful method, but the flow is the hardest to follow at first. Reach for it where map/filter alone don’t suffice.

Chaining #

The three methods compose well.

chaining — even-only then double
const nums = [1, 2, 3, 4, 5];

const result = nums
  .filter((n) => n % 2 === 0)
  .map((n) => n * 2);
// [4, 8]

Because each method returns a new array, chaining is natural.

Other commonly used methods #

search / check
[1, 2, 3].includes(2);            // true
[1, 2, 3].indexOf(2);              // 1
[{id: 'a'}].find((x) => x.id === 'a');    // {id: 'a'}
[1, 2, 3].some((n) => n > 2);     // true (any one)
[1, 2, 3].every((n) => n > 0);    // true (all)
transform — return a new array
[1, 2, 3].slice(1, 3);            // [2, 3]
[1, 2, 3].concat([4, 5]);         // [1, 2, 3, 4, 5]
[3, 1, 2].toSorted();             // [1, 2, 3] (original kept)
to string
[1, 2, 3].join(',');              // '1,2,3'
[1, 2, 3].join(' / ');            // '1 / 2 / 3'

toSorted is a modern method added in ES2023. The old sort mutated the original and caused frequent accidents — toSorted is cleaner.

Spread (...) — unpacking #

Syntax for unpacking and re-grouping objects and arrays.

array spread
const a = [1, 2, 3];
const b = [...a, 4, 5];          // [1, 2, 3, 4, 5]
const copy = [...a];              // [1, 2, 3] — shallow copy

const merged = [...a, ...b];      // concatenate two arrays
object spread
const user = { id: 'u1', name: 'Curtis' };
const updated = { ...user, age: 30 };
// { id: 'u1', name: 'Curtis', age: 30 }

const overridden = { ...user, name: 'another name' };
// { id: 'u1', name: 'another name' }   ← later one wins

This pattern is one of the most-used idioms in JavaScript. It fits cases where you want to build a new value with changes applied, without mutating the original.

Destructuring — unpacking into variables #

Syntax for unpacking values from an object or array into multiple variables at once.

Object destructuring #

object destructuring
const user = { id: 'u1', name: 'Curtis', age: 30 };

const { name, age } = user;
console.log(name);  // Curtis
console.log(age);   // 30

// rename on the way in
const { name: userName } = user;
console.log(userName);   // Curtis

// default value
const { email = 'none' } = user;
console.log(email);   // none

Often used in function parameters too. The props destructuring in the React course is exactly this syntax.

parameter destructuring
function greet({ name, age }) {
  console.log(`hi, ${name} (${age})`);
}

greet({ name: 'Curtis', age: 30 });

Array destructuring #

array destructuring
const [first, second, third] = [10, 20, 30];
console.log(first, second, third);   // 10 20 30

// skip
const [, , third] = [10, 20, 30];
console.log(third);   // 30

// rest for the rest
const [head, ...tail] = [1, 2, 3, 4];
console.log(head);   // 1
console.log(tail);   // [2, 3, 4]

useState’s const [count, setCount] = useState(0) is exactly this syntax.

Dynamic object keys — computed properties #

When you want the key itself to come from a variable.

computed properties
const key = 'name';
const value = 'Curtis';

const user = {
  [key]: value,
  [`is${key}Required`]: true,
};
// { name: 'Curtis', isnameRequired: true }

Inside [...] you can put any expression. Comes up often in real code — e.g., form handlers using the name attribute as a key.

Object.keys / values / entries #

When you want to handle an object like an array.

object as array
const user = { id: 'u1', name: 'Curtis', age: 30 };

Object.keys(user);    // ['id', 'name', 'age']
Object.values(user);  // ['u1', 'Curtis', 30]
Object.entries(user); // [['id', 'u1'], ['name', 'Curtis'], ['age', 30]]

Combined with iteration, very powerful.

iterate via entries
for (const [key, value] of Object.entries(user)) {
  console.log(`${key} = ${value}`);
}

Wrap-up #

What we covered:

  • Objects — key-value pairs, shorthand and method shorthand
  • Arrays — ordered groups; push/pop/shift/unshift mutate the original
  • map/filter/reduce — three methods for transform/filter/accumulate
  • check methods like some/every/find/includes
  • Use spread ... to unpack objects/arrays and shallow-copy
  • Destructuring — unpack object/array into variables
  • Computed properties — { [key]: value }
  • Use Object.keys/values/entries to handle objects like arrays

In the next post (#6 Strings and Template Literals) we cover string handling — common methods, template literals, and regex basics.

X