Advanced Data Types Β· Astro Tech Blog

Advanced Data Types

Iterables

Iterables are objects that can be iterated over with for...of. Built-in iterables include arrays, strings, Map, Set, and more.

for (let char of "hello") {
  console.log(char); // β†’ "h", "e", "l", "l", "o"
}

for (let num of [1, 2, 3]) {
  console.log(num); // β†’ 1, 2, 3
}

Making an object iterable (Symbol.iterator)

let range = {
  from: 1,
  to: 5,

  [Symbol.iterator]() {
    this.current = this.from;
    return {
      next: () => {
        if (this.current <= this.to) {
          return { value: this.current++, done: false };
        }
        return { done: true };
      }
    };
  }
};

for (let num of range) {
  console.log(num); // β†’ 1, 2, 3, 4, 5
}

// Spread also works
console.log([...range]); // β†’ [1, 2, 3, 4, 5]

Explicit Iteration

let arr = [10, 20, 30];
let iterator = arr[Symbol.iterator]();

console.log(iterator.next()); // β†’ { value: 10, done: false }
console.log(iterator.next()); // β†’ { value: 20, done: false }
console.log(iterator.next()); // β†’ { value: 30, done: false }
console.log(iterator.next()); // β†’ { value: undefined, done: true }

String is Iterable

for (let char of "hi 🌍") {
  console.log(char); // β†’ "h", "i", " ", "🌍"
}
// Works with emojis (UTF-16 surrogate pairs) correctly!

Array.from

Creates an array from any iterable or array-like:

Array.from("hello");    // β†’ ["h", "e", "l", "l", "o"]
Array.from(new Set([1, 2, 3])); // β†’ [1, 2, 3]

// With mapping function
Array.from("hello", c => c.toUpperCase()); // β†’ ["H", "E", "L", "L", "O"]

// From array-like (has length, indexed)
Array.from({ length: 5 }, (_, i) => i * 2); // β†’ [0, 2, 4, 6, 8]

Map and Set

Map

A Map is a key-value collection where keys can be ANY type (not just strings):

let map = new Map();

map.set("name", "Alice");    // String key
map.set(42, "answer");       // Number key
map.set(true, "yes");        // Boolean key
map.set({ id: 1 }, "user");  // Object key

map.get("name");  // β†’ "Alice"
map.get(42);      // β†’ "answer"
map.get(true);    // β†’ "yes"
map.has(42);      // β†’ true
map.delete(42);   // β†’ true
map.size;         // β†’ 3
map.clear();      // Empty the map

Map vs Object

FeatureObjectMap
Key typeString or SymbolAny type
Key orderInteger keys sorted, others insertion orderInsertion order
SizeManual counting.size property
Iterationfor...in, Object.keys()for...of, .forEach()
PerformanceOptimized for few keysOptimized for frequent additions/removals

Iterating Map

let map = new Map([
  ["name", "Alice"],
  ["age", 30],
  ["city", "New York"]
]);

// Keys
for (let key of map.keys()) {
  console.log(key); // β†’ "name", "age", "city"
}

// Values
for (let value of map.values()) {
  console.log(value); // β†’ "Alice", 30, "New York"
}

// Entries
for (let [key, value] of map) {
  console.log(`${key}: ${value}`);
}

// forEach
map.forEach((value, key) => console.log(`${key}: ${value}`));

Creating Map from Object

let obj = { name: "Alice", age: 30 };
let map = new Map(Object.entries(obj));
console.log(map.get("name")); // β†’ "Alice"

// Back to object
let obj2 = Object.fromEntries(map);

Set

A Set stores unique values of any type:

let set = new Set();

set.add(1);
set.add(2);
set.add(3);
set.add(2); // Duplicate β€” ignored!
set.add(1); // Duplicate β€” ignored!

set.size; // β†’ 3
set.has(2); // β†’ true
set.delete(2);
set.has(2); // β†’ false

Iterating Set

let set = new Set(["apple", "banana", "orange"]);

for (let value of set) {
  console.log(value);
}

set.forEach(value => console.log(value));

console.log([...set]); // β†’ ["apple", "banana", "orange"]

Practical Set Usage

// Remove duplicates from array
let arr = [1, 2, 2, 3, 3, 3, 4];
let unique = [...new Set(arr)]; // β†’ [1, 2, 3, 4]

// Set operations
let a = new Set([1, 2, 3, 4]);
let b = new Set([3, 4, 5, 6]);

// Union
let union = new Set([...a, ...b]); // β†’ Set {1, 2, 3, 4, 5, 6}

// Intersection
let intersection = new Set([...a].filter(x => b.has(x))); // β†’ Set {3, 4}

// Difference
let difference = new Set([...a].filter(x => !b.has(x))); // β†’ Set {1, 2}
Demo: Map and Set Demo
JavaScript
// Map with object keys
let visits = new Map();
let user1 = { name: 'Alice' };
let user2 = { name: 'Bob' };

visits.set(user1, new Date());
visits.set(user2, new Date());

document.write('Visits count: ' + visits.size + '<br>');
document.write('Alice visited: ' + visits.get(user1) + '<br>');

// Set β€” remove duplicates
let numbers = [1, 2, 2, 3, 3, 3, 4, 5, 5];
let unique = [...new Set(numbers)];
document.write('Unique: ' + unique.join(', ') + '<br>');

// Practical: word counting
let text = 'the quick brown fox jumps over the lazy dog';
let words = text.split(' ');
let wordSet = new Set(words);
document.write('Unique words: ' + wordSet.size + '<br>');
document.write('Total words: ' + words.length + '<br>');
Live Output Window

WeakMap and WeakSet

WeakMap and WeakSet are special collections where keys/values are weakly referenced β€” if an object has no other references, it gets garbage collected.

WeakMap

Keys must be objects (not primitives). No iteration methods.

let weakMap = new WeakMap();

let obj = {};
weakMap.set(obj, "some data");
obj = null; // The entry is automatically removed from weakMap!

// Use case: additional data for objects without leaking memory
let visitsCount = new WeakMap();

function countVisit(user) {
  let count = visitsCount.get(user) || 0;
  visitsCount.set(user, count + 1);
}

WeakSet

Similar β€” objects only, no iteration:

let weakSet = new WeakSet();

let user1 = { name: "Alice" };
let user2 = { name: "Bob" };

weakSet.add(user1);
weakSet.add(user2);

weakSet.has(user1); // β†’ true
// When user1 is garbage collected, it's removed from weakSet

Use Cases

  • Caching data tied to DOM elements
  • Tracking objects without preventing GC
  • Private data storage

Object.keys, values, entries

These are methods for plain objects (not Map):

let user = { name: "Alice", age: 30, city: "New York" };

Object.keys(user);   // β†’ ["name", "age", "city"]
Object.values(user); // β†’ ["Alice", 30, "New York"]
Object.entries(user); // β†’ [["name", "Alice"], ["age", 30], ["city", "New York"]]

Loop with entries

for (let [key, value] of Object.entries(user)) {
  console.log(`${key}: ${value}`);
}

Transforming Objects

let prices = { apple: 1.5, banana: 0.8, orange: 1.2 };

// Double all prices
let doubled = Object.fromEntries(
  Object.entries(prices).map(([key, value]) => [key, value * 2])
);
// β†’ { apple: 3, banana: 1.6, orange: 2.4 }

// Filter β€” only items under $1
let cheap = Object.fromEntries(
  Object.entries(prices).filter(([key, value]) => value < 1)
);
// β†’ { banana: 0.8 }

Destructuring Assignment

Extract values from arrays or objects into variables in one line.

Array Destructuring

let arr = ["Alice", 30, "New York"];

let [name, age, city] = arr;
console.log(name); // β†’ "Alice"
console.log(age);  // β†’ 30

// Skip elements
let [first, , third] = [1, 2, 3, 4, 5];
console.log(first); // β†’ 1
console.log(third); // β†’ 3

// Rest pattern
let [head, ...tail] = [1, 2, 3, 4];
console.log(head); // β†’ 1
console.log(tail); // β†’ [2, 3, 4]

// Default values
let [a = 0, b = 0] = [5];
console.log(a); // β†’ 5
console.log(b); // β†’ 0

// Swapping variables
let x = 10, y = 20;
[x, y] = [y, x];
console.log(x); // β†’ 20
console.log(y); // β†’ 10

Object Destructuring

let user = { name: "Alice", age: 30, city: "New York" };

let { name, age } = user;
console.log(name); // β†’ "Alice"
console.log(age);  // β†’ 30

// Rename variables
let { name: userName, age: userAge } = user;
console.log(userName); // β†’ "Alice"

// Default values
let { name, salary = 50000 } = user;
console.log(salary); // β†’ 50000

// Rest
let { name, ...rest } = user;
console.log(rest); // β†’ { age: 30, city: "New York" }

// Nested destructuring
let person = {
  name: "Alice",
  address: { city: "NYC", zip: 10001 }
};

let { address: { city, zip } } = person;
console.log(city); // β†’ "NYC"

Function Parameter Destructuring

function printUser({ name, age, city = "Unknown" }) {
  console.log(`${name}, ${age}, ${city}`);
}

printUser({ name: "Alice", age: 30 });
// β†’ "Alice, 30, Unknown"

// Array parameter
function sum([a, b, ...rest]) {
  return a + b + rest.reduce((s, n) => s + n, 0);
}

sum([1, 2, 3, 4, 5]); // β†’ 15
Demo: Destructuring Demo
JavaScript
// Array destructuring
let colors = ['red', 'green', 'blue', 'yellow'];
let [primary, secondary, ...others] = colors;

document.write('Primary: ' + primary + '<br>');
document.write('Secondary: ' + secondary + '<br>');
document.write('Others: ' + others.join(', ') + '<br>');

// Object destructuring
let user = { name: 'Alice', age: 30, email: 'alice@example.com' };
let { name, email } = user;

document.write('<br>Name: ' + name + '<br>');
document.write('Email: ' + email + '<br>');

// Practical: function with options object
function createUser({ name, age = 18, role = 'user' }) {
return { name, age, role };
}

let alice = createUser({ name: 'Alice', age: 25 });
document.write('<br>Created user:<br>');
for (let [key, val] of Object.entries(alice)) {
document.write(key + ': ' + val + '<br>');
}
Live Output Window

Date and Time

JavaScript’s Date object handles dates and times.

Creating Dates

// Current date/time
let now = new Date();
console.log(now); // β†’ "Tue Jun 09 2026 12:00:00 GMT+..."

// From timestamp (milliseconds since Jan 1, 1970 UTC)
let epoch = new Date(0);
console.log(epoch); // β†’ "Thu Jan 01 1970 01:00:00 GMT+..."

// From string
let date = new Date("2026-06-09");
let date2 = new Date("2026-06-09T10:30:00");

// From components (month is 0-based!)
let date3 = new Date(2026, 5, 9, 10, 30, 0); // June 9, 2026, 10:30:00

Getting Date Components

let date = new Date(2026, 5, 9, 10, 30, 45);

date.getFullYear();   // β†’ 2026
date.getMonth();      // β†’ 5 (0-based! 0=Jan, 5=Jun)
date.getDate();       // β†’ 9 (day of month)
date.getDay();        // β†’ 2 (0=Sun, 1=Mon, 2=Tue)
date.getHours();      // β†’ 10
date.getMinutes();    // β†’ 30
date.getSeconds();    // β†’ 45
date.getMilliseconds(); // β†’ 0
date.getTime();       // β†’ timestamp in ms

// UTC versions
date.getUTCFullYear();
date.getUTCMonth();
// etc.

Setting Date Components

let date = new Date();

date.setFullYear(2027);
date.setMonth(0);     // January
date.setDate(15);
date.setHours(12);
date.setMinutes(0);
date.setSeconds(0);

Date Math

let start = new Date(2026, 5, 1);
let end = new Date(2026, 5, 15);

let diffMs = end - start;        // Difference in milliseconds
let diffDays = diffMs / (1000 * 60 * 60 * 24); // β†’ 14

// Add days
let future = new Date();
future.setDate(future.getDate() + 7); // +7 days

Formatting

let date = new Date();

date.toString();       // β†’ "Tue Jun 09 2026 12:00:00 GMT+..."
date.toDateString();   // β†’ "Tue Jun 09 2026"
date.toTimeString();   // β†’ "12:00:00 GMT+..."
date.toISOString();    // β†’ "2026-06-09T10:30:00.000Z"
date.toLocaleDateString(); // β†’ "6/9/2026"
date.toLocaleTimeString(); // β†’ "12:00:00 PM"

// Custom formatting with options
date.toLocaleDateString("en-US", {
  weekday: "long",
  year: "numeric",
  month: "long",
  day: "numeric"
}); // β†’ "Tuesday, June 9, 2026"

Date.now()

let timestamp = Date.now(); // Current time in ms β€” faster than new Date().getTime()

JSON Methods, toJSON

JSON (JavaScript Object Notation) is a lightweight data format.

JSON.stringify

Converts a JavaScript value to a JSON string:

let user = {
  name: "Alice",
  age: 30,
  isAdmin: false,
  courses: ["JS", "HTML"],
  address: null
};

let json = JSON.stringify(user);
console.log(json);
// β†’ {"name":"Alice","age":30,"isAdmin":false,"courses":["JS","HTML"],"address":null}

What JSON.stringify handles

JSON.stringify(1);          // β†’ "1"
JSON.stringify("hello");    // β†’ "\"hello\""
JSON.stringify(true);       // β†’ "true"
JSON.stringify(null);       // β†’ "null"
JSON.stringify([1, 2, 3]); // β†’ "[1,2,3]"
JSON.stringify({ a: 1 });  // β†’ "{\"a\":1}"

What it skips

JSON.stringify(undefined);  // β†’ undefined (not string)
JSON.stringify(Symbol());   // β†’ undefined
JSON.stringify(function(){}); // β†’ undefined

let obj = {
  a: 1,
  b: undefined,  // Skipped
  c: Symbol(),   // Skipped
  d: function(){} // Skipped
};
// β†’ "{\"a\":1}"

Replacer β€” custom filtering

let user = { name: "Alice", age: 30, password: "secret" };

// Array of keys to include
JSON.stringify(user, ["name", "age"]);
// β†’ "{\"name\":\"Alice\",\"age\":30}"

// Function
JSON.stringify(user, (key, value) => {
  if (key === "password") return undefined; // Skip
  return value;
});

JSON.parse

Parses JSON string back to JavaScript:

let str = '{"name":"Alice","age":30,"isAdmin":false}';
let user = JSON.parse(str);

console.log(user.name); // β†’ "Alice"

Reviver β€” transform values during parse

let data = '{"name":"Alice","birth":"2026-06-09T10:30:00.000Z"}';

let user = JSON.parse(data, (key, value) => {
  if (key === "birth") return new Date(value);
  return value;
});

console.log(user.birth); // β†’ Date object

// Now you can use date methods
console.log(user.birth.getFullYear()); // β†’ 2026

toJSON

Objects can define custom JSON serialization:

let user = {
  name: "Alice",
  age: 30,
  toJSON() {
    return { name: this.name, age: this.age, type: "user" };
  }
};

JSON.stringify(user);
// β†’ {"name":"Alice","age":30,"type":"user"}

// Date has built-in toJSON
let date = new Date();
date.toJSON(); // β†’ "2026-06-09T10:30:00.000Z"
Demo: JSON Demo
JavaScript
let user = {
name: 'Alice',
age: 30,
skills: ['JS', 'Python', 'HTML']
};

// Convert to JSON string
let json = JSON.stringify(user, null, 2);
document.write('<pre>' + json + '</pre>');

// Parse back
let parsed = JSON.parse(json);
document.write('<br>Parsed name: ' + parsed.name + '<br>');
document.write('Parsed skills: ' + parsed.skills.join(', ') + '<br>');

// Deep clone with JSON
let clone = JSON.parse(JSON.stringify(user));
clone.name = 'Bob';
document.write('Original: ' + user.name + ', Clone: ' + clone.name + '<br>');
Live Output Window