javascript
examples
examples.js⚡javascript
/**
* =====================================================
* 7.4 OBJECT STATIC METHODS - EXAMPLES
* =====================================================
* Comprehensive examples of Object static methods
*/
// =====================================================
// EXAMPLE 1: Object.keys(), Object.values(), Object.entries()
// =====================================================
console.log('=== Example 1: keys(), values(), entries() ===');
const user = {
name: 'Alice',
age: 30,
email: 'alice@example.com',
role: 'admin',
};
// Object.keys() - get all enumerable property names
const keys = Object.keys(user);
console.log('Keys:', keys); // ["name", "age", "email", "role"]
// Object.values() - get all enumerable property values
const values = Object.values(user);
console.log('Values:', values); // ["Alice", 30, "alice@example.com", "admin"]
// Object.entries() - get [key, value] pairs
const entries = Object.entries(user);
console.log('Entries:', entries);
// [["name", "Alice"], ["age", 30], ["email", "alice@example.com"], ["role", "admin"]]
// Iterate with destructuring
console.log('\nIterating with entries:');
for (const [key, value] of Object.entries(user)) {
console.log(` ${key}: ${value}`);
}
// =====================================================
// EXAMPLE 2: Object.assign()
// =====================================================
console.log('\n=== Example 2: Object.assign() ===');
// Merge objects
const defaults = { theme: 'dark', language: 'en', notifications: true };
const userPrefs = { theme: 'light', fontSize: 16 };
const settings = Object.assign({}, defaults, userPrefs);
console.log('Merged settings:', settings);
// { theme: "light", language: "en", notifications: true, fontSize: 16 }
// Clone an object (shallow)
const original = { a: 1, b: { nested: true } };
const clone = Object.assign({}, original);
console.log('Clone:', clone);
// Note: Shallow copy - nested objects are still referenced
clone.b.nested = false;
console.log('Original affected:', original.b.nested); // false
// Multiple sources
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { c: 3, a: 99 }; // Later overrides earlier
const combined = Object.assign({}, obj1, obj2, obj3);
console.log('Combined:', combined); // { a: 99, b: 2, c: 3 }
// =====================================================
// EXAMPLE 3: Object.fromEntries()
// =====================================================
console.log('\n=== Example 3: Object.fromEntries() ===');
// Create object from entries array
const entriesArray = [
['name', 'Bob'],
['age', 25],
['city', 'NYC'],
];
const person = Object.fromEntries(entriesArray);
console.log('From entries:', person); // { name: "Bob", age: 25, city: "NYC" }
// Create object from Map
const map = new Map([
['x', 10],
['y', 20],
['z', 30],
]);
const coords = Object.fromEntries(map);
console.log('From Map:', coords); // { x: 10, y: 20, z: 30 }
// Transform object using entries + fromEntries
const prices = { apple: 1.5, banana: 0.75, cherry: 2.0 };
// Double all prices
const doubledPrices = Object.fromEntries(
Object.entries(prices).map(([key, value]) => [key, value * 2])
);
console.log('Doubled prices:', doubledPrices);
// Filter properties
const expensiveItems = Object.fromEntries(
Object.entries(prices).filter(([, value]) => value >= 1)
);
console.log('Expensive items:', expensiveItems); // { apple: 1.5, cherry: 2.0 }
// =====================================================
// EXAMPLE 4: Object.create()
// =====================================================
console.log('\n=== Example 4: Object.create() ===');
// Create object with specific prototype
const animalProto = {
speak() {
console.log(`${this.name} says ${this.sound}`);
},
};
const dog = Object.create(animalProto);
dog.name = 'Rex';
dog.sound = 'Woof!';
dog.speak(); // "Rex says Woof!"
// Create object with null prototype (no inherited properties)
const pureDict = Object.create(null);
pureDict.key = 'value';
console.log('Pure dict toString:', pureDict.toString); // undefined
// Create with property descriptors
const immutableConfig = Object.create(null, {
apiUrl: {
value: 'https://api.example.com',
writable: false,
enumerable: true,
configurable: false,
},
timeout: {
value: 5000,
writable: false,
enumerable: true,
configurable: false,
},
});
console.log('Immutable config:', immutableConfig);
immutableConfig.apiUrl = 'changed';
console.log('After attempted change:', immutableConfig.apiUrl); // unchanged
// =====================================================
// EXAMPLE 5: Object.is()
// =====================================================
console.log('\n=== Example 5: Object.is() ===');
// Regular comparisons work like ===
console.log('5 === 5:', Object.is(5, 5)); // true
console.log("'a' === 'a':", Object.is('a', 'a')); // true
console.log('{} === {}:', Object.is({}, {})); // false (different refs)
// But handles edge cases differently
console.log('\nEdge cases:');
console.log('NaN === NaN with ===:', NaN === NaN); // false
console.log('NaN === NaN with Object.is:', Object.is(NaN, NaN)); // true!
console.log('+0 === -0 with ===:', +0 === -0); // true
console.log('+0 === -0 with Object.is:', Object.is(+0, -0)); // false!
// Practical use: Check for NaN
const value = 0 / 0; // NaN
if (Object.is(value, NaN)) {
console.log('Value is NaN');
}
// =====================================================
// EXAMPLE 6: Object.hasOwn()
// =====================================================
console.log('\n=== Example 6: Object.hasOwn() ===');
const obj = {
name: 'Test',
value: 42,
};
// Check own properties
console.log("Has 'name':", Object.hasOwn(obj, 'name')); // true
console.log("Has 'value':", Object.hasOwn(obj, 'value')); // true
console.log("Has 'toString':", Object.hasOwn(obj, 'toString')); // false (inherited)
// Safe even with overridden hasOwnProperty
const dangerousObj = {
data: 'important',
hasOwnProperty: function () {
return 'gotcha!';
},
};
console.log('\nSafe check with hasOwn:');
console.log(Object.hasOwn(dangerousObj, 'data')); // true
// Works with null prototype objects
const nullProtoObj = Object.create(null);
nullProtoObj.key = 'value';
console.log("Null proto has 'key':", Object.hasOwn(nullProtoObj, 'key')); // true
// =====================================================
// EXAMPLE 7: Object.getOwnPropertyNames() vs Object.keys()
// =====================================================
console.log('\n=== Example 7: getOwnPropertyNames() vs keys() ===');
const example = { visible: true };
Object.defineProperty(example, 'hidden', {
value: 'secret',
enumerable: false,
});
console.log('Object.keys():', Object.keys(example));
// ["visible"]
console.log('getOwnPropertyNames():', Object.getOwnPropertyNames(example));
// ["visible", "hidden"]
// Built-in array properties example
const arr = [1, 2, 3];
console.log('\nArray keys:', Object.keys(arr));
// ["0", "1", "2"]
console.log('Array getOwnPropertyNames:', Object.getOwnPropertyNames(arr));
// ["0", "1", "2", "length"]
// =====================================================
// EXAMPLE 8: Object.getOwnPropertySymbols()
// =====================================================
console.log('\n=== Example 8: getOwnPropertySymbols() ===');
const sym1 = Symbol('id');
const sym2 = Symbol('secret');
const symbolObj = {
name: 'Regular property',
[sym1]: 12345,
[sym2]: 'hidden data',
};
console.log('Regular keys:', Object.keys(symbolObj));
// ["name"]
console.log('Symbol keys:', Object.getOwnPropertySymbols(symbolObj));
// [Symbol(id), Symbol(secret)]
// Access symbol values
console.log('Symbol value:', symbolObj[sym1]); // 12345
// =====================================================
// EXAMPLE 9: Reflect.ownKeys() - All Keys
// =====================================================
console.log('\n=== Example 9: Reflect.ownKeys() ===');
const sym = Symbol('mySymbol');
const mixedObj = {
regular: 'value',
};
Object.defineProperty(mixedObj, 'hidden', {
value: 'non-enumerable',
enumerable: false,
});
mixedObj[sym] = 'symbol value';
console.log('Reflect.ownKeys():', Reflect.ownKeys(mixedObj));
// ["regular", "hidden", Symbol(mySymbol)]
// =====================================================
// EXAMPLE 10: Object.freeze()
// =====================================================
console.log('\n=== Example 10: Object.freeze() ===');
const frozenConfig = Object.freeze({
appName: 'MyApp',
version: '1.0.0',
features: ['feature1', 'feature2'],
});
console.log('Is frozen:', Object.isFrozen(frozenConfig)); // true
// Cannot modify
frozenConfig.appName = 'ChangedApp';
console.log('appName after attempt:', frozenConfig.appName); // "MyApp"
// Cannot add
frozenConfig.newProp = 'new';
console.log('Has newProp:', 'newProp' in frozenConfig); // false
// Cannot delete
delete frozenConfig.version;
console.log('version still exists:', frozenConfig.version); // "1.0.0"
// WARNING: Nested arrays/objects are NOT frozen
frozenConfig.features.push('feature3');
console.log('Features modified:', frozenConfig.features); // Has 3 items!
// =====================================================
// EXAMPLE 11: Object.seal()
// =====================================================
console.log('\n=== Example 11: Object.seal() ===');
const sealedObj = Object.seal({
name: 'Sealed',
count: 0,
});
console.log('Is sealed:', Object.isSealed(sealedObj)); // true
// CAN modify values
sealedObj.name = 'Modified';
sealedObj.count = 100;
console.log('After modification:', sealedObj); // { name: "Modified", count: 100 }
// CANNOT add properties
sealedObj.newProp = 'test';
console.log('newProp exists:', 'newProp' in sealedObj); // false
// CANNOT delete properties
delete sealedObj.name;
console.log('name still exists:', 'name' in sealedObj); // true
// =====================================================
// EXAMPLE 12: Object.preventExtensions()
// =====================================================
console.log('\n=== Example 12: Object.preventExtensions() ===');
const limitedObj = Object.preventExtensions({
existing: 'I exist',
});
console.log('Is extensible:', Object.isExtensible(limitedObj)); // false
// CAN modify existing
limitedObj.existing = 'Modified';
console.log('After modification:', limitedObj.existing);
// CAN delete
delete limitedObj.existing;
console.log('After delete:', limitedObj); // {}
// CANNOT add new
limitedObj.newProp = 'test';
console.log('Has newProp:', 'newProp' in limitedObj); // false
// =====================================================
// EXAMPLE 13: Object.getPrototypeOf() / setPrototypeOf()
// =====================================================
console.log('\n=== Example 13: Prototype Methods ===');
const animal = {
type: 'animal',
speak() {
console.log('Some sound');
},
};
const cat = {
name: 'Whiskers',
meow() {
console.log('Meow!');
},
};
// Get prototype
console.log('cat prototype:', Object.getPrototypeOf(cat) === Object.prototype); // true
// Set prototype (use sparingly - performance impact)
Object.setPrototypeOf(cat, animal);
console.log('cat prototype now:', Object.getPrototypeOf(cat) === animal); // true
cat.speak(); // "Some sound"
console.log('cat type:', cat.type); // "animal"
// Better: Use Object.create() from the start
const betterCat = Object.create(animal);
betterCat.name = 'Felix';
betterCat.meow = function () {
console.log('Meow!');
};
// =====================================================
// EXAMPLE 14: Object.getOwnPropertyDescriptor(s)
// =====================================================
console.log('\n=== Example 14: getOwnPropertyDescriptor(s) ===');
const product = {
name: 'Widget',
get price() {
return this._price;
},
set price(value) {
this._price = value;
},
};
product._price = 99.99;
// Single property descriptor
const nameDesc = Object.getOwnPropertyDescriptor(product, 'name');
console.log('name descriptor:', nameDesc);
/*
{
value: "Widget",
writable: true,
enumerable: true,
configurable: true
}
*/
// Accessor property descriptor
const priceDesc = Object.getOwnPropertyDescriptor(product, 'price');
console.log('price descriptor:', priceDesc);
/*
{
get: [Function: get price],
set: [Function: set price],
enumerable: true,
configurable: true
}
*/
// All descriptors
const allDesc = Object.getOwnPropertyDescriptors(product);
console.log('All descriptors keys:', Object.keys(allDesc));
// =====================================================
// EXAMPLE 15: Deep Clone with Descriptors
// =====================================================
console.log('\n=== Example 15: Deep Clone with Descriptors ===');
function deepCloneWithDescriptors(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (hash.has(obj)) return hash.get(obj);
const clone = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
hash.set(obj, clone);
// Deep clone nested objects
for (const key of Reflect.ownKeys(obj)) {
const value = obj[key];
if (value && typeof value === 'object') {
clone[key] = deepCloneWithDescriptors(value, hash);
}
}
return clone;
}
const original2 = {
name: 'Original',
nested: {
value: 42,
},
};
Object.defineProperty(original2, 'hidden', {
value: 'secret',
enumerable: false,
});
const deepClone = deepCloneWithDescriptors(original2);
deepClone.nested.value = 999;
console.log('Original nested value:', original2.nested.value); // 42
console.log('Clone nested value:', deepClone.nested.value); // 999
console.log('Clone has hidden:', Object.hasOwn(deepClone, 'hidden')); // true
// =====================================================
// EXAMPLE 16: Object Transformation Patterns
// =====================================================
console.log('\n=== Example 16: Object Transformation Patterns ===');
const data = {
firstName: 'John',
lastName: 'Doe',
age: 30,
_private: 'secret',
email: 'john@example.com',
};
// 1. Pick specific properties
const pick = (obj, ...keys) =>
Object.fromEntries(Object.entries(obj).filter(([key]) => keys.includes(key)));
console.log('Pick:', pick(data, 'firstName', 'lastName'));
// 2. Omit specific properties
const omit = (obj, ...keys) =>
Object.fromEntries(
Object.entries(obj).filter(([key]) => !keys.includes(key))
);
console.log('Omit:', omit(data, '_private', 'age'));
// 3. Map values
const mapValues = (obj, fn) =>
Object.fromEntries(
Object.entries(obj).map(([key, value]) => [key, fn(value, key)])
);
console.log(
'Map values (uppercase strings):',
mapValues(data, (v) => (typeof v === 'string' ? v.toUpperCase() : v))
);
// 4. Filter by value
const filterByValue = (obj, predicate) =>
Object.fromEntries(
Object.entries(obj).filter(([key, value]) => predicate(value, key))
);
console.log(
'Filter strings:',
filterByValue(data, (v) => typeof v === 'string')
);
// 5. Rename keys
const renameKeys = (obj, keyMap) =>
Object.fromEntries(
Object.entries(obj).map(([key, value]) => [keyMap[key] || key, value])
);
console.log(
'Rename keys:',
renameKeys(data, { firstName: 'first', lastName: 'last' })
);
// =====================================================
// EXAMPLE 17: Object Comparison Utilities
// =====================================================
console.log('\n=== Example 17: Object Comparison Utilities ===');
// Shallow equality check
function shallowEqual(obj1, obj2) {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
return keys1.every((key) => Object.is(obj1[key], obj2[key]));
}
const a = { x: 1, y: 2 };
const b = { x: 1, y: 2 };
const c = { x: 1, y: 3 };
console.log('a shallow equals b:', shallowEqual(a, b)); // true
console.log('a shallow equals c:', shallowEqual(a, c)); // false
// Find differences between objects
function objectDiff(obj1, obj2) {
const allKeys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
const diff = {};
for (const key of allKeys) {
if (!Object.is(obj1[key], obj2[key])) {
diff[key] = { old: obj1[key], new: obj2[key] };
}
}
return diff;
}
const oldState = { name: 'Alice', age: 30, city: 'NYC' };
const newState = { name: 'Alice', age: 31, country: 'USA' };
console.log('Diff:', objectDiff(oldState, newState));
/*
{
age: { old: 30, new: 31 },
city: { old: "NYC", new: undefined },
country: { old: undefined, new: "USA" }
}
*/
// =====================================================
// EXAMPLE 18: Object.groupBy() (ES2024)
// =====================================================
console.log('\n=== Example 18: Object.groupBy() (ES2024) ===');
// Note: Object.groupBy is ES2024, polyfill for older environments
const groupBy = (arr, keyFn) => {
return arr.reduce((acc, item) => {
const key = keyFn(item);
(acc[key] ||= []).push(item);
return acc;
}, {});
};
const people = [
{ name: 'Alice', department: 'Engineering', level: 'Senior' },
{ name: 'Bob', department: 'Marketing', level: 'Junior' },
{ name: 'Charlie', department: 'Engineering', level: 'Junior' },
{ name: 'Diana', department: 'Marketing', level: 'Senior' },
];
// Group by department
const byDepartment = groupBy(people, (p) => p.department);
console.log('By department:', byDepartment);
// Group by level
const byLevel = groupBy(people, (p) => p.level);
console.log('By level:', byLevel);
// Group by first letter of name
const byFirstLetter = groupBy(people, (p) => p.name[0]);
console.log('By first letter:', byFirstLetter);
// =====================================================
// EXAMPLE 19: Creating Mixins with Object Methods
// =====================================================
console.log('\n=== Example 19: Creating Mixins ===');
const loggableMixin = {
log(message) {
console.log(`[${this.name || 'Object'}] ${message}`);
},
};
const serializableMixin = {
toJSON() {
const obj = {};
for (const key of Object.keys(this)) {
if (!key.startsWith('_')) {
obj[key] = this[key];
}
}
return JSON.stringify(obj);
},
fromJSON(json) {
Object.assign(this, JSON.parse(json));
return this;
},
};
const timestampMixin = {
touch() {
this._lastModified = new Date().toISOString();
},
get lastModified() {
return this._lastModified;
},
};
// Apply mixins to an object
function applyMixins(target, ...mixins) {
return Object.assign(target, ...mixins);
}
const entity = applyMixins(
{ name: 'MyEntity', value: 42 },
loggableMixin,
serializableMixin,
timestampMixin
);
entity.log('Hello!');
entity.touch();
console.log('Serialized:', entity.toJSON());
console.log('Last modified:', entity.lastModified);
// =====================================================
// EXAMPLE 20: Proxy with Object Methods
// =====================================================
console.log('\n=== Example 20: Proxy with Object Methods ===');
function createValidatedObject(schema) {
const data = {};
return new Proxy(data, {
set(target, property, value) {
const validator = schema[property];
if (validator && !validator(value)) {
throw new TypeError(`Invalid value for ${property}: ${value}`);
}
target[property] = value;
return true;
},
get(target, property) {
return target[property];
},
ownKeys(target) {
return Object.keys(target);
},
getOwnPropertyDescriptor(target, property) {
return Object.getOwnPropertyDescriptor(target, property);
},
});
}
const userSchema = {
name: (v) => typeof v === 'string' && v.length > 0,
age: (v) => typeof v === 'number' && v >= 0 && v <= 150,
email: (v) => typeof v === 'string' && v.includes('@'),
};
const validatedUser = createValidatedObject(userSchema);
validatedUser.name = 'Alice';
validatedUser.age = 30;
validatedUser.email = 'alice@example.com';
console.log('Validated user:', Object.assign({}, validatedUser));
try {
validatedUser.age = -5; // Invalid!
} catch (e) {
console.log('Validation error:', e.message);
}
console.log('\n=== All Examples Complete ===');