Back to Articles

JavaScript Basics Chapter 2: The Data Type Kingdom

July 21, 20256 min read
javascriptdata-typesprimitivesobjectsnullundefinedbooleannumberstringsymbolbigint
JavaScript Basics Chapter 2: The Data Type Kingdom

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:


"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!"