Data Types
JavaScript Data Types
Section titled “JavaScript Data Types”JavaScript has a rich type system that includes both primitive and reference types. Understanding data types and their behaviors is fundamental to writing effective JavaScript code.
Array Operations and Methods
Section titled “Array Operations and Methods”Array Creation and Basic Operations
Section titled “Array Creation and Basic Operations”// Different ways to create arraysconst arr1 = [1, 2, 3, 4, 5];const arr2 = new Array(5); // [undefined × 5]const arr3 = new Array(1, 2, 3); // [1, 2, 3]const arr4 = Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']const arr5 = Array.of(1, 2, 3); // [1, 2, 3]
// Array.from with mapping functionconst numbers = Array.from({ length: 5 }, (_, i) => i * 2); // [0, 2, 4, 6, 8]const range = Array.from({ length: 10 }, (_, i) => i + 1); // [1, 2, 3, ..., 10]
// Sparse arraysconst sparse = [1, , , 4]; // [1, undefined × 2, 4]console.log(sparse.length); // 4console.log(1 in sparse); // falseconsole.log(3 in sparse); // true
// Array-like objectsconst arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 };const realArray = Array.from(arrayLike); // ['a', 'b', 'c']
Array Mutating Methods
Section titled “Array Mutating Methods”const fruits = ['apple', 'banana', 'orange'];
// Adding elementsfruits.push('grape'); // Returns new length: 4fruits.unshift('mango'); // Returns new length: 5fruits.splice(2, 0, 'kiwi'); // Insert at index 2
console.log(fruits); // ['mango', 'apple', 'kiwi', 'banana', 'orange', 'grape']
// Removing elementsconst lastFruit = fruits.pop(); // 'grape'const firstFruit = fruits.shift(); // 'mango'const removed = fruits.splice(1, 2); // Remove 2 elements starting at index 1
console.log(fruits); // ['apple', 'orange']console.log(removed); // ['kiwi', 'banana']
// Sorting and reversingconst numbers = [3, 1, 4, 1, 5, 9, 2, 6];numbers.sort(); // [1, 1, 2, 3, 4, 5, 6, 9]numbers.reverse(); // [9, 6, 5, 4, 3, 2, 1, 1]
// Custom sortingconst people = [ { name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }, { name: 'Charlie', age: 35 }];
people.sort((a, b) => a.age - b.age); // Sort by age ascendingpeople.sort((a, b) => b.name.localeCompare(a.name)); // Sort by name descending
// Fill methodconst zeros = new Array(5).fill(0); // [0, 0, 0, 0, 0]const matrix = Array(3).fill(null).map(() => Array(3).fill(0));
Array Non-Mutating Methods
Section titled “Array Non-Mutating Methods”const original = [1, 2, 3, 4, 5];
// Concatenationconst combined = original.concat([6, 7, 8]); // [1, 2, 3, 4, 5, 6, 7, 8]const spread = [...original, 6, 7, 8]; // Same result with spread
// Slicingconst subset = original.slice(1, 4); // [2, 3, 4]const copy = original.slice(); // [1, 2, 3, 4, 5] (shallow copy)
// Joiningconst joined = original.join(', '); // '1, 2, 3, 4, 5'const noSeparator = original.join(''); // '12345'
// Searchingconst index = original.indexOf(3); // 2const lastIndex = original.lastIndexOf(3); // 2const includes = original.includes(3); // true
// Findingconst found = original.find(x => x > 3); // 4const foundIndex = original.findIndex(x => x > 3); // 3const foundLast = original.findLast(x => x > 3); // 5 (ES2023)const foundLastIndex = original.findLastIndex(x => x > 3); // 4 (ES2023)
Functional Array Methods
Section titled “Functional Array Methods”const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Map - transform each elementconst doubled = numbers.map(x => x * 2); // [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]const squared = numbers.map(x => x ** 2); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// Filter - select elements based on conditionconst evens = numbers.filter(x => x % 2 === 0); // [2, 4, 6, 8, 10]const greaterThanFive = numbers.filter(x => x > 5); // [6, 7, 8, 9, 10]
// Reduce - accumulate valuesconst sum = numbers.reduce((acc, curr) => acc + curr, 0); // 55const product = numbers.reduce((acc, curr) => acc * curr, 1); // 3628800const max = numbers.reduce((acc, curr) => Math.max(acc, curr)); // 10
// Complex reduce examplesconst people = [ { name: 'Alice', age: 30, department: 'Engineering' }, { name: 'Bob', age: 25, department: 'Marketing' }, { name: 'Charlie', age: 35, department: 'Engineering' }, { name: 'Diana', age: 28, department: 'Marketing' }];
// Group by departmentconst byDepartment = people.reduce((acc, person) => { if (!acc[person.department]) { acc[person.department] = []; } acc[person.department].push(person); return acc;}, {});
// Calculate average ageconst averageAge = people.reduce((sum, person, index, array) => { sum += person.age; return index === array.length - 1 ? sum / array.length : sum;}, 0);
// ReduceRight - process from right to leftconst rightToLeft = [1, 2, 3, 4].reduceRight((acc, curr) => acc + curr); // 10
// Some and everyconst hasEven = numbers.some(x => x % 2 === 0); // trueconst allPositive = numbers.every(x => x > 0); // trueconst allEven = numbers.every(x => x % 2 === 0); // false
// ForEach - side effectsnumbers.forEach((value, index, array) => { console.log(`Index ${index}: ${value}`);});
Advanced Array Techniques
Section titled “Advanced Array Techniques”// Chaining methodsconst result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] .filter(x => x % 2 === 0) // [2, 4, 6, 8, 10] .map(x => x * x) // [4, 16, 36, 64, 100] .reduce((sum, x) => sum + x, 0); // 220
// Flattening arraysconst nested = [[1, 2], [3, 4], [5, 6]];const flattened1 = nested.flat(); // [1, 2, 3, 4, 5, 6]
const deepNested = [1, [2, [3, [4, 5]]]];const flattened2 = deepNested.flat(3); // [1, 2, 3, 4, 5]const completelyFlat = deepNested.flat(Infinity); // [1, 2, 3, 4, 5]
// FlatMap - map then flattenconst words = ['hello', 'world'];const letters = words.flatMap(word => word.split('')); // ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']
// Array deduplicationconst duplicates = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];const unique = [...new Set(duplicates)]; // [1, 2, 3, 4]
// Complex deduplication by propertyconst users = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 1, name: 'Alice' }, { id: 3, name: 'Charlie' }];
const uniqueUsers = users.filter((user, index, array) => array.findIndex(u => u.id === user.id) === index);
// Intersection and differenceconst arr1 = [1, 2, 3, 4, 5];const arr2 = [3, 4, 5, 6, 7];
const intersection = arr1.filter(x => arr2.includes(x)); // [3, 4, 5]const difference = arr1.filter(x => !arr2.includes(x)); // [1, 2]const symmetricDiff = [...difference, ...arr2.filter(x => !arr1.includes(x))]; // [1, 2, 6, 7]
// Array chunkingfunction chunk(array, size) { const chunks = []; for (let i = 0; i < array.length; i += size) { chunks.push(array.slice(i, i + size)); } return chunks;}
const chunked = chunk([1, 2, 3, 4, 5, 6, 7, 8], 3); // [[1, 2, 3], [4, 5, 6], [7, 8]]
// Array rotationfunction rotateLeft(array, positions) { const n = positions % array.length; return [...array.slice(n), ...array.slice(0, n)];}
function rotateRight(array, positions) { const n = positions % array.length; return [...array.slice(-n), ...array.slice(0, -n)];}
const original = [1, 2, 3, 4, 5];const leftRotated = rotateLeft(original, 2); // [3, 4, 5, 1, 2]const rightRotated = rotateRight(original, 2); // [4, 5, 1, 2, 3]
Object Operations
Section titled “Object Operations”Object Creation and Property Access
Section titled “Object Creation and Property Access”// Different ways to create objectsconst obj1 = {}; // Object literalconst obj2 = new Object(); // Constructorconst obj3 = Object.create(null); // No prototypeconst obj4 = Object.create(Object.prototype); // Explicit prototype
// Property definitionconst person = { firstName: 'John', lastName: 'Doe', age: 30, 'full-name': 'John Doe', // Property with special characters 42: 'meaning of life' // Numeric property};
// Property accessconsole.log(person.firstName); // 'John'console.log(person['lastName']); // 'Doe'console.log(person['full-name']); // 'John Doe'console.log(person[42]); // 'meaning of life'
// Dynamic property accessconst propName = 'age';console.log(person[propName]); // 30
// Property existence checkingconsole.log('firstName' in person); // trueconsole.log(person.hasOwnProperty('firstName')); // trueconsole.log(person.nonExistent !== undefined); // false
Object Methods and Operations
Section titled “Object Methods and Operations”const source1 = { a: 1, b: 2 };const source2 = { b: 3, c: 4 };const target = { x: 10 };
// Object.assign - shallow copy/mergeconst merged = Object.assign(target, source1, source2);console.log(merged); // { x: 10, a: 1, b: 3, c: 4 }
// Spread operator - alternative to Object.assignconst spreadMerged = { ...target, ...source1, ...source2 };
// Object.keys, values, entriesconst data = { name: 'Alice', age: 30, city: 'New York' };const keys = Object.keys(data); // ['name', 'age', 'city']const values = Object.values(data); // ['Alice', 30, 'New York']const entries = Object.entries(data); // [['name', 'Alice'], ['age', 30], ['city', 'New York']]
// Object.fromEntries - reverse of Object.entriesconst reconstructed = Object.fromEntries(entries); // { name: 'Alice', age: 30, city: 'New York' }
// Transform object with entriesconst doubled = Object.fromEntries( Object.entries({ a: 1, b: 2, c: 3 }).map(([key, value]) => [key, value * 2])); // { a: 2, b: 4, c: 6 }
// Object.freeze, seal, preventExtensionsconst obj = { a: 1, b: 2 };
Object.freeze(obj); // No modifications allowedObject.seal(obj); // No property addition/deletion, but modification allowedObject.preventExtensions(obj); // No property addition, but deletion and modification allowed
console.log(Object.isFrozen(obj)); // trueconsole.log(Object.isSealed(obj)); // trueconsole.log(Object.isExtensible(obj)); // false
Advanced Object Techniques
Section titled “Advanced Object Techniques”// Property descriptorsconst obj = {};Object.defineProperty(obj, 'readOnly', { value: 'cannot change', writable: false, enumerable: true, configurable: false});
Object.defineProperty(obj, 'hidden', { value: 'secret', writable: true, enumerable: false, // Won't show in Object.keys() configurable: true});
// Getter and setter propertiesconst user = { _firstName: '', _lastName: '',
get fullName() { return `${this._firstName} ${this._lastName}`.trim(); },
set fullName(value) { [this._firstName, this._lastName] = value.split(' '); },
get firstName() { return this._firstName; }, set firstName(value) { this._firstName = value; },
get lastName() { return this._lastName; }, set lastName(value) { this._lastName = value; }};
user.fullName = 'John Doe';console.log(user.firstName); // 'John'console.log(user.lastName); // 'Doe'
// Object destructuring with defaults and renamingconst config = { host: 'localhost', port: 3000, ssl: false};
const { host, port = 8080, // Default value ssl: useSSL, // Rename database = 'mydb' // Default for missing property} = config;
// Nested destructuringconst user = { name: 'Alice', address: { street: '123 Main St', city: 'Boston', country: 'USA' }};
const { name, address: { city, country }} = user;
// Rest in destructuringconst { name, ...rest } = { name: 'Alice', age: 30, city: 'Boston' };console.log(rest); // { age: 30, city: 'Boston' }
// Object cloningfunction shallowClone(obj) { return { ...obj };}
function deepClone(obj) { if (obj === null || typeof obj !== 'object') return obj; if (obj instanceof Date) return new Date(obj.getTime()); if (obj instanceof Array) return obj.map(deepClone); if (obj instanceof Object) { const cloned = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { cloned[key] = deepClone(obj[key]); } } return cloned; }}
// Modern deep cloning (where supported)const original = { a: 1, b: { c: 2 }, d: new Date() };const cloned = structuredClone(original);
// Object comparisonfunction deepEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (typeof a !== typeof b) return false;
if (typeof a === 'object') { const keysA = Object.keys(a); const keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;
for (const key of keysA) { if (!keysB.includes(key)) return false; if (!deepEqual(a[key], b[key])) return false; }
return true; }
return false;}
Set and Map
Section titled “Set and Map”Set Operations
Section titled “Set Operations”// Set creation and basic operationsconst set1 = new Set([1, 2, 3, 4, 5]);const set2 = new Set('hello'); // Set { 'h', 'e', 'l', 'o' }
// Adding and removing elementsset1.add(6);set1.add(6); // Duplicates are ignoredset1.delete(1);console.log(set1.has(2)); // trueconsole.log(set1.size); // 5
// Set iterationfor (const value of set1) { console.log(value);}
set1.forEach(value => console.log(value));
// Convert to arrayconst arrayFromSet = [...set1];const arrayFromSet2 = Array.from(set1);
// Set operationsfunction setUnion(setA, setB) { return new Set([...setA, ...setB]);}
function setIntersection(setA, setB) { return new Set([...setA].filter(x => setB.has(x)));}
function setDifference(setA, setB) { return new Set([...setA].filter(x => !setB.has(x)));}
function setSymmetricDifference(setA, setB) { return new Set([ ...[...setA].filter(x => !setB.has(x)), ...[...setB].filter(x => !setA.has(x)) ]);}
const setA = new Set([1, 2, 3, 4]);const setB = new Set([3, 4, 5, 6]);
console.log(setUnion(setA, setB)); // Set { 1, 2, 3, 4, 5, 6 }console.log(setIntersection(setA, setB)); // Set { 3, 4 }console.log(setDifference(setA, setB)); // Set { 1, 2 }console.log(setSymmetricDifference(setA, setB)); // Set { 1, 2, 5, 6 }
// Practical Set usagefunction removeDuplicates(array) { return [...new Set(array)];}
function hasUniqueElements(array) { return array.length === new Set(array).size;}
function findCommonElements(arrays) { if (arrays.length === 0) return [];
const sets = arrays.map(arr => new Set(arr)); const firstSet = sets[0];
return [...firstSet].filter(item => sets.every(set => set.has(item)) );}
Map Operations
Section titled “Map Operations”// Map creation and basic operationsconst map1 = new Map();const map2 = new Map([ ['key1', 'value1'], ['key2', 'value2'], [1, 'number key'], [true, 'boolean key']]);
// Adding and retrieving valuesmap1.set('name', 'Alice');map1.set('age', 30);map1.set('city', 'New York');
console.log(map1.get('name')); // 'Alice'console.log(map1.has('age')); // trueconsole.log(map1.size); // 3
// Object as key (unique feature of Map)const objKey = { id: 1 };map1.set(objKey, 'object value');console.log(map1.get(objKey)); // 'object value'
// Map iterationfor (const [key, value] of map1) { console.log(`${key}: ${value}`);}
for (const key of map1.keys()) { console.log(key);}
for (const value of map1.values()) { console.log(value);}
map1.forEach((value, key) => { console.log(`${key} => ${value}`);});
// Convert between Map and Objectfunction mapToObject(map) { const obj = {}; for (const [key, value] of map) { obj[key] = value; } return obj;}
function objectToMap(obj) { return new Map(Object.entries(obj));}
// Practical Map usageclass Cache { constructor(maxSize = 100) { this.cache = new Map(); this.maxSize = maxSize; }
get(key) { if (this.cache.has(key)) { // Move to end (LRU behavior) const value = this.cache.get(key); this.cache.delete(key); this.cache.set(key, value); return value; } return undefined; }
set(key, value) { if (this.cache.has(key)) { this.cache.delete(key); } else if (this.cache.size >= this.maxSize) { // Remove oldest entry const firstKey = this.cache.keys().next().value; this.cache.delete(firstKey); }
this.cache.set(key, value); }
has(key) { return this.cache.has(key); }
clear() { this.cache.clear(); }
size() { return this.cache.size; }}
// Frequency counter with Mapfunction countFrequency(items) { const frequency = new Map();
for (const item of items) { frequency.set(item, (frequency.get(item) || 0) + 1); }
return frequency;}
const words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'];const freq = countFrequency(words);console.log(freq); // Map { 'apple' => 3, 'banana' => 2, 'cherry' => 1 }
// Group by with Mapfunction groupBy(items, keyFn) { const groups = new Map();
for (const item of items) { const key = keyFn(item); if (!groups.has(key)) { groups.set(key, []); } groups.get(key).push(item); }
return groups;}
const people = [ { name: 'Alice', age: 25, department: 'Engineering' }, { name: 'Bob', age: 30, department: 'Marketing' }, { name: 'Charlie', age: 25, department: 'Engineering' }];
const byDepartment = groupBy(people, person => person.department);const byAge = groupBy(people, person => person.age);
WeakMap and WeakSet
Section titled “WeakMap and WeakSet”WeakMap Usage Patterns
Section titled “WeakMap Usage Patterns”// Private data with WeakMapconst privateData = new WeakMap();
class User { constructor(name, email) { privateData.set(this, { name, email, created: new Date() }); }
getName() { return privateData.get(this).name; }
setName(name) { privateData.get(this).name = name; }
getEmail() { return privateData.get(this).email; }
toString() { const data = privateData.get(this); return `User: ${data.name} (${data.email})`; }}
// Metadata associationconst elementMetadata = new WeakMap();
function addMetadata(element, metadata) { elementMetadata.set(element, metadata);}
function getMetadata(element) { return elementMetadata.get(element);}
// DOM elements with metadataconst button = document.createElement('button');addMetadata(button, { clicked: 0, created: new Date(), type: 'primary'});
button.addEventListener('click', () => { const meta = getMetadata(button); meta.clicked++; console.log(`Button clicked ${meta.clicked} times`);});
// Caching with automatic cleanupconst computeCache = new WeakMap();
function expensiveComputation(obj) { if (computeCache.has(obj)) { console.log('Cache hit'); return computeCache.get(obj); }
console.log('Computing...'); const result = performExpensiveOperation(obj); computeCache.set(obj, result); return result;}
function performExpensiveOperation(obj) { // Simulate expensive computation return Object.keys(obj).length * Math.random();}
WeakSet Usage Patterns
Section titled “WeakSet Usage Patterns”// Object trackingconst processedObjects = new WeakSet();
function processObject(obj) { if (processedObjects.has(obj)) { console.log('Object already processed'); return; }
// Process the object console.log('Processing object...');
// Mark as processed processedObjects.add(obj);}
// Preventing circular references in serializationconst serializing = new WeakSet();
function customStringify(obj) { if (serializing.has(obj)) { return '"[Circular Reference]"'; }
if (typeof obj === 'object' && obj !== null) { serializing.add(obj);
try { if (Array.isArray(obj)) { const items = obj.map(item => customStringify(item)); return `[${items.join(',')}]`; } else { const props = Object.keys(obj).map(key => `"${key}":${customStringify(obj[key])}` ); return `{${props.join(',')}}`; } } finally { serializing.delete(obj); } }
return JSON.stringify(obj);}
// Test circular referenceconst circularObj = { name: 'test' };circularObj.self = circularObj;console.log(customStringify(circularObj)); // {"name":"test","self":"[Circular Reference]"}
// Access controlconst authorizedObjects = new WeakSet();
function authorize(obj) { authorizedObjects.add(obj);}
function isAuthorized(obj) { return authorizedObjects.has(obj);}
function secureOperation(obj) { if (!isAuthorized(obj)) { throw new Error('Access denied'); }
// Perform secure operation console.log('Secure operation performed');}
This comprehensive guide to JavaScript data types and structures provides the foundation for effective data manipulation and organization in JavaScript applications.
Master these data structures to efficiently organize and manipulate data in your JavaScript applications.