The Story Continues: Chapter 2
Having met the three variable siblings in Chapter 1, we now venture into the diverse kingdom of data types, where every value belongs to a tribe with its own customs and behaviors.
Chapter 2: The Data Type Kingdom
In JavaScript Land, every value belongs to one of several tribes, each with their own customs and behaviors.
The Primitive Tribes
The Number Clan
// All numbers in JavaScript are floating-point let integer = 42; let decimal = 3.14159; let scientific = 2.998e8; // 299,800,000 let negative = -273.15; // Special number values let infinity = Infinity; let negInfinity = -Infinity; let notANumber = NaN; // Fun fact: NaN is not equal to itself! console.log(NaN === NaN); // false (the only value in JS that isn't equal to itself) console.log(Number.isNaN(NaN)); // true (the correct way to check)
The String Tribe
// Multiple ways to create strings let single = 'Single quotes'; let double = "Double quotes"; let template = `Template literals with ${single}`; // String methods are like magical spells let spell = "Abracadabra"; console.log(spell.length); // 11 console.log(spell.toUpperCase()); // "ABRACADABRA" console.log(spell.slice(0, 5)); // "Abrac" console.log(spell.includes("cada")); // true
The Boolean Clan (The Truth Tellers)
let truth = true; let falsehood = false; // The fascinating world of truthiness and falsiness // Falsy values (the "falsy gang"): console.log(Boolean(false)); // false console.log(Boolean(0)); // false console.log(Boolean(-0)); // false console.log(Boolean(0n)); // false (BigInt zero) console.log(Boolean("")); // false (empty string) console.log(Boolean(null)); // false console.log(Boolean(undefined)); // false console.log(Boolean(NaN)); // false // Everything else is truthy! console.log(Boolean("0")); // true (string "0") console.log(Boolean([])); // true (empty array) console.log(Boolean({})); // true (empty object)
The null and undefined Twins
// null: intentional absence of value let intentionallyEmpty = null; // undefined: variable exists but has no value let notYetAssigned; console.log(notYetAssigned); // undefined // The confusing part console.log(typeof null); // "object" (famous JavaScript bug!) console.log(typeof undefined); // "undefined" console.log(null == undefined); // true (they're similar) console.log(null === undefined); // false (but not identical)
The Symbol Tribe (The Unique Ones)
// Symbols are always unique let sym1 = Symbol("description"); let sym2 = Symbol("description"); console.log(sym1 === sym2); // false - always unique! // Often used as object keys to avoid conflicts const PRIVATE_PROP = Symbol("private"); let obj = { name: "Public", [PRIVATE_PROP]: "Hidden" };
The BigInt Giants
// For numbers larger than Number.MAX_SAFE_INTEGER let huge = 1234567890123456789012345678901234567890n; let alsoHuge = BigInt("9007199254740991999999"); // Can't mix BigInt with regular numbers // console.log(huge + 1); // TypeError console.log(huge + 1n); // Works with BigInt
The Object Kingdom
Objects are the rulers of JavaScript Land, and everything else pays tribute to them.
// Objects are collections of key-value pairs let kingdom = { name: "JavaScript Land", population: Infinity, ruler: "The Great Function", // Methods are functions stored as properties speak: function() { return `Welcome to ${this.name}!`; }, // ES6 shorthand for methods greet() { return this.speak(); } }; // Multiple ways to access properties console.log(kingdom.name); // Dot notation console.log(kingdom["population"]); // Bracket notation let prop = "ruler"; console.log(kingdom[prop]); // Dynamic access
Optional Chaining and Nullish Coalescing
// Optional chaining (?.) - safely access nested properties const user = { profile: { social: { twitter: "@alice" } } }; // Traditional way (verbose and error-prone) const twitter1 = user && user.profile && user.profile.social && user.profile.social.twitter; // Optional chaining (clean and safe) const twitter2 = user?.profile?.social?.twitter; const instagram = user?.profile?.social?.instagram; // undefined (no error) // Works with arrays and function calls too const firstHobby = user?.hobbies?.[0]; const result = user?.getName?.(); // Nullish coalescing (??) - default values for null/undefined const username = user?.name ?? "Anonymous"; const theme = user?.preferences?.theme ?? "light"; // Different from || operator console.log("" || "default"); // "default" (empty string is falsy) console.log("" ?? "default"); // "" (empty string is not nullish) console.log(null ?? "default"); // "default" console.log(undefined ?? "default"); // "default"
Dynamic Imports and Top-level Await
// Dynamic imports - load modules conditionally async function loadModule(condition) { if (condition) { const module = await import('./heavy-module.js'); return module.default(); } } // Top-level await (in modules) // utils.js const data = await fetch('https://api.example.com/data').then(r => r.json()); export { data }; // Code splitting with dynamic imports const LazyComponent = lazy(() => import('./LazyComponent'));
The Plot Thickens
Now that we've met the inhabitants of the Data Type Kingdom, our story takes us to the Operator Guild - a group of symbols that manipulate and compare our data types in fascinating ways.
Continue the adventure:
- Previous: Chapter 1: The Tale of Three Siblings
- Next: Chapter 3: The Operator Guild
- Table of Contents: JavaScript Guide - Table of Contents
"In the Data Type Kingdom, every value has a place and every place has its rules. But beware - some residents aren't quite what they appear to be!"
