Docs

README

2.2 Data Types

šŸ“š Table of Contents

  1. •Overview of Data Types
  2. •Number
  3. •String
  4. •Boolean
  5. •Null
  6. •Undefined
  7. •Symbol
  8. •BigInt
  9. •Object (Reference Type)
  10. •Type Checking

Overview of Data Types

JavaScript has 8 data types, divided into two categories:

Primitive Types (7 types)

Primitives are immutable and stored by value:

TypeExampletypeof Result
Number42, 3.14, NaN"number"
String"hello", 'world'"string"
Booleantrue, false"boolean"
Nullnull"object" (bug!)
Undefinedundefined"undefined"
SymbolSymbol("id")"symbol"
BigInt9007199254740991n"bigint"

Reference Type (1 type)

Objects are mutable and stored by reference:

TypeExampletypeof Result
Object{}, [], function(){}"object" or "function"

Primitive vs Reference:

// PRIMITIVE - copied by value
let a = 10;
let b = a; // b gets a COPY of the value
b = 20;
console.log(a); // 10 (unchanged)
console.log(b); // 20

// REFERENCE - copied by reference
let obj1 = { name: 'John' };
let obj2 = obj1; // obj2 points to SAME object
obj2.name = 'Jane';
console.log(obj1.name); // "Jane" (changed!)
console.log(obj2.name); // "Jane"

Visual Representation:

PRIMITIVES (stored by value):
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”     ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  a: 10  │     │  b: 20  │   ← Separate copies
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜     ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

OBJECTS (stored by reference):
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”     ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ obj1: ā—ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā–ŗā”‚ { name: "Jane" } │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜     ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”            ā–²
│ obj2: ā—ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜   ← Both point to same object
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Number

JavaScript has a single number type for both integers and floating-point numbers, using 64-bit floating-point format (IEEE 754).

Creating Numbers:

// Integer
let count = 42;
let negative = -17;

// Floating-point (decimal)
let price = 19.99;
let tiny = 0.001;

// Scientific notation
let big = 5e6; // 5,000,000
let small = 5e-6; // 0.000005

// Binary, Octal, Hexadecimal
let binary = 0b1010; // 10 in decimal
let octal = 0o755; // 493 in decimal
let hex = 0xff; // 255 in decimal

Special Number Values:

// Infinity
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(Infinity + 1); // Infinity

// NaN (Not a Number)
console.log('hello' * 2); // NaN
console.log(Math.sqrt(-1)); // NaN
console.log(NaN === NaN); // false (!) - NaN is not equal to itself

// Checking for NaN
console.log(isNaN(NaN)); // true
console.log(isNaN('hello')); // true (coerces to NaN)
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN('hello')); // false (doesn't coerce)

Number Precision:

// Safe integer range: -(2^53 - 1) to (2^53 - 1)
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991

// Precision issues with floating-point
console.log(0.1 + 0.2); // 0.30000000000000004 (not 0.3!)
console.log(0.1 + 0.2 === 0.3); // false

// How to compare floats safely
const a = 0.1 + 0.2;
const b = 0.3;
console.log(Math.abs(a - b) < Number.EPSILON); // true

// Number limits
console.log(Number.MAX_VALUE); // ~1.79e+308
console.log(Number.MIN_VALUE); // ~5e-324 (smallest positive)

Number Methods:

// Converting to Number
Number('42'); // 42
Number('3.14'); // 3.14
Number('hello'); // NaN
Number(true); // 1
Number(false); // 0
Number(null); // 0
Number(undefined); // NaN

// Parsing
parseInt('42'); // 42
parseInt('42.9'); // 42 (truncates decimal)
parseInt('42px'); // 42 (parses until non-digit)
parseInt('px42'); // NaN (starts with non-digit)
parseFloat('3.14'); // 3.14
parseFloat('3.14.15'); // 3.14 (stops at second dot)

// Formatting
let num = 3.14159;
num.toFixed(2); // "3.14" (string!)
num.toPrecision(4); // "3.142" (string!)
num.toString(); // "3.14159"
num.toString(2); // "11.001..." (binary string)
num.toString(16); // "3.243..." (hex string)

// Checking
Number.isInteger(42); // true
Number.isInteger(42.0); // true
Number.isInteger(42.5); // false
Number.isFinite(42); // true
Number.isFinite(Infinity); // false

String

Strings are sequences of characters used to represent text. They are immutable in JavaScript.

Creating Strings:

// Single quotes
let single = 'Hello';

// Double quotes
let double = 'World';

// Template literals (backticks) - ES6
let template = `Hello World`;

// Template literals with expressions
let name = 'John';
let greeting = `Hello, ${name}!`; // "Hello, John!"

// Multi-line strings
let multiLine = `Line 1
Line 2
Line 3`;

// Escape sequences
let escaped = 'He said "Hello"';
let newline = 'Line1\nLine2';
let tab = 'Col1\tCol2';

String Properties and Methods:

let str = 'Hello, World!';

// Length
str.length; // 13

// Access characters
str[0]; // "H"
str.charAt(0); // "H"
str.at(-1); // "!" (negative index, ES2022)

// Case conversion
str.toUpperCase(); // "HELLO, WORLD!"
str.toLowerCase(); // "hello, world!"

// Searching
str.indexOf('World'); // 7
str.lastIndexOf('o'); // 8
str.includes('World'); // true
str.startsWith('Hello'); // true
str.endsWith('!'); // true

// Extracting
str.slice(0, 5); // "Hello"
str.slice(-6); // "World!"
str.substring(0, 5); // "Hello"
str.substr(0, 5); // "Hello" (deprecated)

// Modifying (returns new string)
str.replace('World', 'JS'); // "Hello, JS!"
str.replaceAll('o', '0'); // "Hell0, W0rld!"
str.trim(); // Removes whitespace from ends
str.padStart(20, '*'); // "*******Hello, World!"
str.padEnd(20, '*'); // "Hello, World!*******"
str.repeat(2); // "Hello, World!Hello, World!"

// Splitting
str.split(', '); // ["Hello", "World!"]
str.split(''); // ["H", "e", "l", "l", "o", ...]

Template Literals (Template Strings):

// Basic interpolation
let name = 'Alice';
let age = 30;
console.log(`${name} is ${age} years old`);

// Expressions in templates
let a = 5;
let b = 10;
console.log(`Sum: ${a + b}`); // "Sum: 15"
console.log(`Comparison: ${a > b}`); // "Comparison: false"

// Function calls in templates
function greet(name) {
  return `Hello, ${name}!`;
}
console.log(`Greeting: ${greet('Bob')}`);

// Multi-line
let html = `
<div>
    <h1>Title</h1>
    <p>Paragraph</p>
</div>
`;

// Tagged templates (advanced)
function highlight(strings, ...values) {
  return strings.reduce((result, str, i) => {
    return `${result}${str}<mark>${values[i] || ''}</mark>`;
  }, '');
}
let user = 'John';
let action = 'logged in';
console.log(highlight`User ${user} has ${action}`);

Immutability:

let str = 'Hello';
str[0] = 'Y'; // Doesn't work (no error, but no change)
console.log(str); // "Hello" (unchanged)

// To "modify", create a new string
str = 'Y' + str.slice(1);
console.log(str); // "Yello"

Boolean

Booleans represent logical values: true or false.

Creating Booleans:

let isActive = true;
let isComplete = false;

// From comparison
let isEqual = 5 === 5; // true
let isGreater = 10 > 5; // true
let isLess = 3 < 1; // false

// From Boolean() conversion
Boolean(1); // true
Boolean(0); // false
Boolean('hello'); // true
Boolean(''); // false

Truthy and Falsy Values:

JavaScript converts values to boolean in logical contexts. Some values are "falsy" (convert to false), all others are "truthy".

// FALSY VALUES (only these 8):
Boolean(false); // false
Boolean(0); // false
Boolean(-0); // false
Boolean(0n); // false (BigInt zero)
Boolean(''); // false (empty string)
Boolean(null); // false
Boolean(undefined); // false
Boolean(NaN); // false

// TRUTHY VALUES (everything else):
Boolean(true); // true
Boolean(1); // true
Boolean(-1); // true
Boolean('hello'); // true
Boolean('false'); // true (non-empty string!)
Boolean([]); // true (empty array!)
Boolean({}); // true (empty object!)
Boolean(function () {}); // true

Practical Use of Truthy/Falsy:

// Conditional checks
let name = '';
if (name) {
  console.log('Has name');
} else {
  console.log('No name'); // This runs
}

// Default values (before ES6)
function greet(name) {
  name = name || 'Guest'; // If falsy, use "Guest"
  return `Hello, ${name}!`;
}

// Double negation to convert to boolean
let value = 'hello';
let boolValue = !!value; // true

// Common patterns
let items = [];
if (items.length) {
  console.log('Has items');
} else {
  console.log('Empty'); // This runs
}

Null

null represents the intentional absence of any value. It's explicitly assigned to indicate "no value" or "empty".

Understanding Null:

let user = null; // Intentionally set to "no value"

console.log(user); // null
console.log(typeof null); // "object" (this is a historical bug!)

// Checking for null
console.log(user === null); // true
console.log(user == null); // true

Null vs Undefined:

let a = null; // Intentionally empty
let b; // Not yet assigned (undefined)
let c = undefined; // Explicitly set to undefined (unusual)

console.log(a); // null
console.log(b); // undefined

// Equality checks
console.log(null == undefined); // true (loose equality)
console.log(null === undefined); // false (strict equality)

// Type checks
console.log(typeof null); // "object" (bug)
console.log(typeof undefined); // "undefined"

When to Use Null:

// Use null to indicate intentional absence
let selectedUser = null;  // No user selected yet

function findUser(id) {
    // Return null if user not found
    if (/* user not found */) {
        return null;
    }
    return { id: id, name: "John" };
}

let user = findUser(123);
if (user === null) {
    console.log("User not found");
}

// Clear a variable
let data = { name: "test" };
data = null;  // Clear the reference

Undefined

undefined means a variable has been declared but not assigned a value.

When Undefined Occurs:

// 1. Declared but not initialized
let x;
console.log(x); // undefined

// 2. Missing function parameters
function greet(name) {
  console.log(name);
}
greet(); // undefined

// 3. Non-existent object properties
let obj = { a: 1 };
console.log(obj.b); // undefined

// 4. Functions without return
function noReturn() {
  let x = 5;
}
console.log(noReturn()); // undefined

// 5. Array elements that don't exist
let arr = [1, 2, 3];
console.log(arr[10]); // undefined

Checking for Undefined:

let x;

// Method 1: Strict equality
if (x === undefined) {
  console.log('x is undefined');
}

// Method 2: typeof (safer for undeclared variables)
if (typeof x === 'undefined') {
  console.log('x is undefined');
}

// Method 3: Void operator comparison
if (x === void 0) {
  console.log('x is undefined');
}

Null vs Undefined - When to Use Which:

// Use UNDEFINED when:
// - Variable hasn't been assigned yet
// - Property doesn't exist
// - Function has no return value
// - Parameter wasn't provided

// Use NULL when:
// - Intentionally setting "no value"
// - Clearing a reference
// - Indicating "not found"
// - API responses for missing data

// Common pattern
function getUser(id) {
  if (id === undefined) {
    throw new Error('ID is required'); // Parameter missing
  }
  let user = database.find(id);
  return user || null; // Return null if not found
}

Symbol

Symbol is a unique and immutable primitive value, introduced in ES6. Used for creating unique identifiers.

Creating Symbols:

// Create a symbol
let sym1 = Symbol();
let sym2 = Symbol();

console.log(sym1 === sym2); // false (always unique!)

// Symbols with descriptions (for debugging)
let id = Symbol('id');
let id2 = Symbol('id');

console.log(id === id2); // false (still unique!)
console.log(id.description); // "id"

Why Use Symbols?

1. Unique Property Keys:

// Prevent property name collisions
const ID = Symbol('id');
const NAME = Symbol('name');

let user = {
  [ID]: 12345,
  [NAME]: 'John',
  name: 'Regular name property',
};

console.log(user[ID]); // 12345
console.log(user[NAME]); // "John"
console.log(user.name); // "Regular name property"

// Symbols are not enumerable by default
console.log(Object.keys(user)); // ["name"]
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id), Symbol(name)]

2. Well-Known Symbols (Built-in):

// Symbol.iterator - define how object is iterated
let range = {
  start: 1,
  end: 5,
  [Symbol.iterator]() {
    let current = this.start;
    let end = this.end;
    return {
      next() {
        if (current <= end) {
          return { value: current++, done: false };
        }
        return { done: true };
      },
    };
  },
};

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

// Symbol.toStringTag - customize Object.prototype.toString
class MyClass {
  get [Symbol.toStringTag]() {
    return 'MyClass';
  }
}
console.log(Object.prototype.toString.call(new MyClass())); // "[object MyClass]"

3. Global Symbol Registry:

// Create/retrieve global symbols
let globalSym = Symbol.for('shared');
let sameGlobalSym = Symbol.for('shared');

console.log(globalSym === sameGlobalSym); // true (same symbol!)

// Get the key for a global symbol
console.log(Symbol.keyFor(globalSym)); // "shared"

// Regular symbols are not in the global registry
let localSym = Symbol('local');
console.log(Symbol.keyFor(localSym)); // undefined

BigInt

BigInt can represent integers of arbitrary size, beyond the safe integer limit of Number.

Creating BigInt:

// Add 'n' suffix
let big = 9007199254740991n;
let huge = 123456789012345678901234567890n;

// Using BigInt() constructor
let fromNumber = BigInt(9007199254740991);
let fromString = BigInt('9007199254740991');

console.log(typeof big); // "bigint"

BigInt Operations:

// Arithmetic works with BigInt
let a = 100n;
let b = 50n;

console.log(a + b); // 150n
console.log(a - b); // 50n
console.log(a * b); // 5000n
console.log(a / b); // 2n (truncates to integer)
console.log(a % b); // 0n

// Comparison works
console.log(a > b); // true
console.log(a === 100n); // true

// But NOT with Number (mixing types)
// console.log(a + 50);  // TypeError!
console.log(a + BigInt(50)); // 150n (convert first)

BigInt Limitations:

// Cannot use with Math methods
// Math.max(1n, 2n);  // TypeError

// Cannot have decimals
// let decimal = 1.5n;  // SyntaxError

// Division truncates (no decimals)
console.log(5n / 2n); // 2n (not 2.5n)

// JSON doesn't support BigInt directly
// JSON.stringify({ big: 1n });  // TypeError
// Workaround:
JSON.stringify({ big: 1n.toString() });

// Loose equality with Number works
console.log(1n == 1); // true
console.log(1n === 1); // false (different types)

When to Use BigInt:

// Working with large IDs
const userId = 9007199254740993n;

// Cryptocurrency amounts (in smallest units)
const satoshis = 100000000n; // 1 Bitcoin

// Financial calculations requiring precision
const cents = 99999999999999999n;

// Timestamps in microseconds
const microseconds = 1638360000000000n;

Object (Reference Type)

While this section focuses on primitives, it's important to understand that Object is the only reference type, and it includes arrays and functions.

Objects Overview:

// Object literal
let person = {
  name: 'John',
  age: 30,
};

// Array (special object)
let numbers = [1, 2, 3];

// Function (callable object)
function greet() {
  return 'Hello';
}

// Checking types
console.log(typeof person); // "object"
console.log(typeof numbers); // "object"
console.log(typeof greet); // "function"
console.log(Array.isArray(numbers)); // true

Reference Behavior:

// Objects are passed by reference
let original = { x: 10 };
let copy = original;

copy.x = 20;
console.log(original.x); // 20 (both point to same object!)

// To create a true copy:
let shallowCopy = { ...original }; // Shallow copy
let deepCopy = JSON.parse(JSON.stringify(original)); // Deep copy (limitations)

Type Checking

Using typeof:

console.log(typeof 42); // "number"
console.log(typeof 'hello'); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (bug!)
console.log(typeof Symbol()); // "symbol"
console.log(typeof 42n); // "bigint"
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function () {}); // "function"

Better Type Checking:

// Check for null specifically
let value = null;
console.log(value === null); // true

// Check for array
Array.isArray([1, 2, 3]); // true
Array.isArray('hello'); // false

// Check for NaN
Number.isNaN(NaN); // true
Number.isNaN('hello'); // false

// Object.prototype.toString for accurate type
function getType(value) {
  return Object.prototype.toString.call(value).slice(8, -1);
}

console.log(getType(42)); // "Number"
console.log(getType('hello')); // "String"
console.log(getType(null)); // "Null"
console.log(getType(undefined)); // "Undefined"
console.log(getType([])); // "Array"
console.log(getType({})); // "Object"
console.log(getType(/regex/)); // "RegExp"
console.log(getType(new Date())); // "Date"

šŸŽÆ Key Takeaways

  1. •7 Primitive Types: Number, String, Boolean, Null, Undefined, Symbol, BigInt
  2. •1 Reference Type: Object (includes Arrays and Functions)
  3. •Primitives are immutable and copied by value
  4. •Objects are mutable and copied by reference
  5. •null = intentional absence, undefined = not yet assigned
  6. •Symbol creates unique identifiers
  7. •BigInt handles integers beyond safe range
  8. •Use typeof for basic checks, but know its quirks (null returns "object")

āž”ļø Next Topic

Continue to 2.3 Type Mechanics to learn about type coercion, casting, and more!

README - JavaScript Tutorial | DeepML