🔢 Data Types

Understanding JavaScript Values

Data Types in JavaScript

JavaScript has dynamic typing - variables can hold different types of values. Understanding data types is crucial for effective programming.

📚 Primitive Data Types

JavaScript has 7 primitive data types that are immutable and stored by value.

1. Number

// Integers and decimals
let age = 25;
let price = 19.99;
let negative = -10;

// Special numeric values
let infinity = Infinity;
let negInfinity = -Infinity;
let notANumber = NaN;  // Not a Number

// Number operations
console.log(10 / 0);        // Infinity
console.log(-10 / 0);       // -Infinity
console.log('text' * 2);    // NaN
console.log(0 / 0);         // NaN

// Checking for NaN
console.log(isNaN(NaN));           // true
console.log(isNaN('hello'));       // true
console.log(Number.isNaN(NaN));    // true (better)
console.log(Number.isNaN('hello')); // false

// Number methods
let num = 3.14159;
console.log(num.toFixed(2));       // '3.14'
console.log(num.toPrecision(3));   // '3.14'
console.log(parseInt('42'));       // 42
console.log(parseFloat('3.14'));   // 3.14

// BigInt for very large numbers
const huge = 9007199254740991n;  // Note the 'n'
const bigInt = BigInt(9007199254740991);
console.log(huge + 1n);  // 9007199254740992n

2. String

// Single or double quotes
let single = 'Hello';
let double = "World";

// Template literals (backticks)
let name = 'John';
let greeting = `Hello, ${name}!`;  // 'Hello, John!'

// Multi-line strings
let multiline = `This is
a multi-line
string`;

// String methods
let text = 'JavaScript';
console.log(text.length);           // 10
console.log(text.toUpperCase());    // 'JAVASCRIPT'
console.log(text.toLowerCase());    // 'javascript'
console.log(text.charAt(0));        // 'J'
console.log(text.indexOf('Script')); // 4
console.log(text.slice(0, 4));      // 'Java'
console.log(text.split(''));        // ['J','a','v','a','S','c','r','i','p','t']

// String concatenation
let first = 'Hello';
let second = 'World';
console.log(first + ' ' + second);  // 'Hello World'
console.log(`${first} ${second}`);  // 'Hello World'

// Escape characters
let quote = "He said, \"Hello!\"";
let path = 'C:\\Users\\John';
let newline = 'Line 1\nLine 2';
let tab = 'Column1\tColumn2';

3. Boolean

// Only two values: true or false
let isActive = true;
let isComplete = false;

// Boolean from comparisons
let isGreater = 10 > 5;        // true
let isEqual = 10 === 10;       // true
let isLess = 5 < 3;            // false

// Logical operations
let and = true && false;       // false
let or = true || false;        // true
let not = !true;               // false

// Truthy and falsy values
// Falsy: false, 0, '', null, undefined, NaN
// Everything else is truthy

console.log(Boolean(0));          // false
console.log(Boolean(''));         // false
console.log(Boolean(null));       // false
console.log(Boolean(undefined));  // false
console.log(Boolean(NaN));        // false

console.log(Boolean(1));          // true
console.log(Boolean('hello'));    // true
console.log(Boolean([]));         // true
console.log(Boolean({}));         // true

4. Undefined

// Variable declared but not assigned
let x;
console.log(x);  // undefined

// Function with no return
function test() {
    // no return statement
}
console.log(test());  // undefined

// Missing object property
let person = { name: 'John' };
console.log(person.age);  // undefined

// Missing array element
let arr = [1, 2, 3];
console.log(arr[10]);  // undefined

5. Null

// Intentional absence of value
let result = null;

// Difference between null and undefined
let notAssigned;           // undefined
let intentionallyEmpty = null;  // null

console.log(notAssigned);           // undefined
console.log(intentionallyEmpty);    // null

// Type checking quirk
console.log(typeof undefined);  // 'undefined'
console.log(typeof null);       // 'object' (historical bug!)

// Checking for null
console.log(result === null);  // true
console.log(result == null);   // true
console.log(result == undefined);  // true (loose equality)

6. Symbol (ES6)

// Unique identifiers
let sym1 = Symbol('description');
let sym2 = Symbol('description');

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

// Use in objects for unique keys
let id = Symbol('id');
let user = {
    name: 'John',
    [id]: 123  // Symbol as property key
};

console.log(user[id]);  // 123
console.log(user.id);   // undefined

// Symbols are not enumerable
for (let key in user) {
    console.log(key);  // Only 'name' (not Symbol)
}

// Global symbol registry
let globalSym1 = Symbol.for('app.id');
let globalSym2 = Symbol.for('app.id');
console.log(globalSym1 === globalSym2);  // true

7. BigInt (ES2020)

// For integers larger than 2^53 - 1
const big = 9007199254740991n;
const alsoHuge = BigInt(9007199254740991);

console.log(big + 1n);  // 9007199254740992n

// Cannot mix with regular numbers
// console.log(big + 1);  // Error!
console.log(big + BigInt(1));  // Works

// Comparison works
console.log(1n < 2);   // true
console.log(2n > 1);   // true
console.log(2n === 2); // false (different types)
console.log(2n == 2);  // true (loose equality)

🎯 Reference Types (Objects)

Object

// Object literal
let person = {
    name: 'John',
    age: 30,
    city: 'New York',
    greet: function() {
        console.log(`Hi, I'm ${this.name}`);
    }
};

// Accessing properties
console.log(person.name);       // 'John' (dot notation)
console.log(person['age']);     // 30 (bracket notation)

// Adding properties
person.country = 'USA';
person['email'] = 'john@example.com';

// Deleting properties
delete person.city;

// Nested objects
let user = {
    name: 'Jane',
    address: {
        street: '123 Main St',
        city: 'Boston',
        zip: '02101'
    }
};
console.log(user.address.city);  // 'Boston'

Array

// Array literal
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, 'hello', true, null, { name: 'John' }];

// Accessing elements
console.log(numbers[0]);  // 1 (zero-indexed)
console.log(numbers[4]);  // 5

// Array properties and methods
console.log(numbers.length);     // 5
numbers.push(6);                 // Add to end
numbers.pop();                   // Remove from end
numbers.unshift(0);              // Add to start
numbers.shift();                 // Remove from start

// Array methods
let doubled = numbers.map(n => n * 2);
let evens = numbers.filter(n => n % 2 === 0);
let sum = numbers.reduce((acc, n) => acc + n, 0);

// Multi-dimensional arrays
let matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];
console.log(matrix[1][1]);  // 5

Function

// Function declaration
function add(a, b) {
    return a + b;
}

// Function expression
const subtract = function(a, b) {
    return a - b;
};

// Arrow function
const multiply = (a, b) => a * b;

// Functions are objects
console.log(typeof add);  // 'function'
add.customProperty = 'I am a property';
console.log(add.customProperty);  // 'I am a property'

Date

// Creating dates
let now = new Date();
let specific = new Date('2025-01-01');
let timestamp = new Date(1640995200000);

// Date methods
console.log(now.getFullYear());   // 2025
console.log(now.getMonth());      // 0-11 (0 = January)
console.log(now.getDate());       // 1-31
console.log(now.getDay());        // 0-6 (0 = Sunday)
console.log(now.getHours());      // 0-23
console.log(now.getMinutes());    // 0-59
console.log(now.getSeconds());    // 0-59

// Formatting
console.log(now.toDateString());      // 'Wed Jan 01 2025'
console.log(now.toTimeString());      // '12:00:00 GMT+0000'
console.log(now.toISOString());       // '2025-01-01T12:00:00.000Z'

🔄 Type Checking

// typeof operator
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('id'));    // 'symbol'
console.log(typeof 123n);            // 'bigint'
console.log(typeof {});              // 'object'
console.log(typeof []);              // 'object' (arrays are objects)
console.log(typeof function() {});   // 'function'

// Better type checking
console.log(Array.isArray([]));              // true
console.log(Array.isArray({}));              // false

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

// instanceof for objects
let date = new Date();
console.log(date instanceof Date);           // true
console.log([] instanceof Array);            // true
console.log({} instanceof Object);           // true

// Object.prototype.toString for accurate type
function getType(value) {
    return Object.prototype.toString.call(value).slice(8, -1);
}
console.log(getType([]));        // 'Array'
console.log(getType({}));        // 'Object'
console.log(getType(null));      // 'Null'
console.log(getType(new Date())); // 'Date'

🔁 Type Conversion

To String

// Explicit conversion
String(123);              // '123'
String(true);             // 'true'
String(null);             // 'null'
String(undefined);        // 'undefined'
String([1, 2, 3]);        // '1,2,3'
String({ a: 1 });         // '[object Object]'

// Using toString()
let num = 42;
num.toString();           // '42'
true.toString();          // 'true'

// Template literals
`${123}`;                 // '123'
`${true}`;                // 'true'

// Implicit conversion
123 + '';                 // '123'
true + '';                // 'true'

To Number

// Explicit conversion
Number('123');            // 123
Number('12.34');          // 12.34
Number('');               // 0
Number(' ');              // 0
Number('hello');          // NaN
Number(true);             // 1
Number(false);            // 0
Number(null);             // 0
Number(undefined);        // NaN

// Using parseInt and parseFloat
parseInt('123');          // 123
parseInt('123.45');       // 123
parseInt('123px');        // 123
parseFloat('123.45');     // 123.45
parseFloat('123.45px');   // 123.45

// Unary plus operator
+'123';                   // 123
+'12.34';                 // 12.34
+true;                    // 1
+false;                   // 0

// Implicit conversion
'5' * 2;                  // 10
'10' / 2;                 // 5
'10' - 5;                 // 5
'5' + 2;                  // '52' (concatenation!)

To Boolean

// Explicit conversion
Boolean(1);               // true
Boolean(0);               // false
Boolean('hello');         // true
Boolean('');              // false
Boolean(null);            // false
Boolean(undefined);       // false
Boolean(NaN);             // false
Boolean({});              // true
Boolean([]);              // true

// Double NOT operator
!!1;                      // true
!!0;                      // false
!!'hello';                // true
!!'';                     // false

// Implicit in conditionals
if ('hello') {            // true
    console.log('truthy');
}

if (0) {                  // false
    console.log('won\'t run');
}

⚖️ Equality Comparisons

// Strict equality (===) - No type conversion
console.log(5 === 5);         // true
console.log(5 === '5');       // false (different types)
console.log(true === 1);      // false
console.log(null === undefined); // false

// Loose equality (==) - With type conversion
console.log(5 == '5');        // true (converts '5' to 5)
console.log(true == 1);       // true (converts true to 1)
console.log(null == undefined); // true
console.log(0 == false);      // true
console.log('' == false);     // true

// Best practice: Use === (strict equality)
// Only use == when specifically checking for null/undefined
if (value == null) {  // Checks for both null and undefined
    console.log('value is null or undefined');
}

// Equivalent to:
if (value === null || value === undefined) {
    console.log('value is null or undefined');
}

// Object equality
let obj1 = { name: 'John' };
let obj2 = { name: 'John' };
let obj3 = obj1;

console.log(obj1 === obj2);   // false (different objects)
console.log(obj1 === obj3);   // true (same reference)

💡 Practical Examples

Input Validation

function validateAge(age) {
    // Convert to number
    age = Number(age);
    
    // Check if valid number
    if (isNaN(age)) {
        return 'Invalid age: not a number';
    }
    
    // Check range
    if (age < 0 || age > 150) {
        return 'Invalid age: out of range';
    }
    
    return 'Valid age';
}

console.log(validateAge(25));      // 'Valid age'
console.log(validateAge('25'));    // 'Valid age'
console.log(validateAge('abc'));   // 'Invalid age: not a number'
console.log(validateAge(-5));      // 'Invalid age: out of range'

Type-Safe Operations

function safeAdd(a, b) {
    // Ensure both are numbers
    a = Number(a);
    b = Number(b);
    
    if (isNaN(a) || isNaN(b)) {
        throw new Error('Both arguments must be numbers');
    }
    
    return a + b;
}

console.log(safeAdd(5, 10));       // 15
console.log(safeAdd('5', '10'));   // 15
// console.log(safeAdd('a', 'b'));  // Error!

Default Values

function greet(name) {
    // Using || for default value
    name = name || 'Guest';
    return `Hello, ${name}!`;
}

// Better: Using ?? (nullish coalescing - ES2020)
function greet2(name) {
    name = name ?? 'Guest';  // Only null/undefined, not falsy
    return `Hello, ${name}!`;
}

console.log(greet());          // 'Hello, Guest!'
console.log(greet('John'));    // 'Hello, John!'
console.log(greet(''));        // 'Hello, Guest!' (empty string is falsy)

console.log(greet2(''));       // 'Hello, !' (keeps empty string)
console.log(greet2(null));     // 'Hello, Guest!'

🎯 Key Takeaways