-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathiii_ObjectMethods.js
More file actions
386 lines (314 loc) · 15.4 KB
/
Copy pathiii_ObjectMethods.js
File metadata and controls
386 lines (314 loc) · 15.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
// ============================================================
// iii — Object Methods in JavaScript
// Interview Ready | ES Version Tagged | Old vs Modern
// ============================================================
// ============================================================
// 1. Object.keys() [ES5 | 2009]
// ============================================================
/*
Returns an array of an object's OWN enumerable property keys.
Does NOT include inherited (prototype) properties.
Interview note:
- Only returns string keys, not Symbol keys
- Useful for iterating over object properties
- Order: integer keys first (sorted), then string keys (insertion order)
*/
const student = { name: 'Buddy', age: 21, education: 'BTech' };
// console.log(Object.keys(student)); // ['name', 'age', 'education']
// Common use — iterate keys
// Object.keys(student).forEach(key => console.log(key, student[key]));
// name Buddy
// age 21
// education BTech
// ============================================================
// 2. Object.values() [ES8 | 2017]
// ============================================================
/*
Returns an array of an object's OWN enumerable property values.
Pairs with Object.keys() — same order, just values instead of keys.
Interview note:
- Old way was: Object.keys(obj).map(k => obj[k]) — ugly!
- Does NOT return values from prototype chain
*/
// console.log(Object.values(student)); // ['Buddy', 21, 'BTech']
// Old way before ES8
// console.log(Object.keys(student).map(k => student[k])); // ['Buddy', 21, 'BTech']
// ============================================================
// 3. Object.entries() [ES8 | 2017]
// ============================================================
/*
Returns an array of [key, value] pairs from an object's OWN properties.
Perfect for looping over objects with both key and value access.
Interview note:
- Pairs perfectly with for...of + destructuring
- Inverse of Object.fromEntries() (ES10)
- Commonly used to transform or filter object properties
*/
const scores = { alice: 90, bob: 85, carol: 92 };
// console.log(Object.entries(scores)); // [['alice', 90], ['bob', 85], ['carol', 92]]
// Looping with destructuring ✨
// for (const [name, score] of Object.entries(scores)) {
// console.log(`${name}: ${score}`);
// }
// alice: 90
// bob: 85
// carol: 92
// Transform object values using entries + fromEntries
const curved = Object.fromEntries(
Object.entries(scores).map(([k, v]) => [k, v + 5])
);
// console.log(curved); // { alice: 95, bob: 90, carol: 97 }
// ============================================================
// 4. Object.fromEntries() [ES10 | 2019]
// ============================================================
/*
Converts an array of [key, value] pairs (or a Map) back into an object.
Exact opposite of Object.entries().
Interview note:
- Great for transforming objects via entries pipeline
- Also works with Map directly — common interview use case
*/
const entries = [['name', 'Alice'], ['age', 25]];
// console.log(Object.fromEntries(entries)); // { name: 'Alice', age: 25 }
// Convert Map to Object ✨
const map = new Map([['theme', 'dark'], ['lang', 'en']]);
// console.log(Object.fromEntries(map)); // { theme: 'dark', lang: 'en' }
// Power combo — filter object by value
const passing = Object.fromEntries(
Object.entries(scores).filter(([, v]) => v >= 90)
);
// console.log(passing); // { alice: 90, carol: 92 }
// ============================================================
// 5. Object.assign() [ES6 | 2015]
// ============================================================
/*
Used to assign properties from one or more source objects to a target object.
Copies OWN enumerable properties from source object(s) into target.
Syntax: Object.assign(target, ...sources)
Returns: the modified target object.
Interview note:
- SHALLOW copy only — nested objects are still references!
- Mutates the target — always pass {} to avoid mutating original
- Later sources override earlier ones (same key)
- Modern alternative: spread { ...obj } does the same thing
*/
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 }; // b overrides obj1.b
const merged = Object.assign({}, obj1, obj2);
// console.log(merged); // { a: 1, b: 3, c: 4 }
// console.log(obj1); // { a: 1, b: 2 } ← unchanged (used {} as target)
// Shallow copy trap ⚠️
const original = { x: 1, nested: { y: 2 } };
const copy = Object.assign({}, original);
copy.nested.y = 99;
// console.log(original.nested.y); // 99 ← original also mutated!
// Modern spread alternative (ES6) ✨
const merged2 = { ...obj1, ...obj2 };
// console.log(merged2); // { a: 1, b: 3, c: 4 }
// ============================================================
// 6. Object.create() [ES5 | 2009]
// ============================================================
/*
Creates a new object using an existing object as its prototype.
Syntax: Object.create(proto, propertiesObject?)
Interview note:
- Pure prototypal inheritance — no class or constructor needed
- Object.create(null) → object with NO prototype (pure hash map)
- Difference from new: Object.create() sets prototype directly,
new uses the constructor's .prototype property
*/
const coder = {
isStudying: false,
introduction() {
return `My name is ${this.name}. Studying: ${this.isStudying}`;
}
};
const me = Object.create(coder); // me.__proto__ === coder
me.name = 'Buddy';
me.isStudying = true;
// console.log(me.introduction()); // 'My name is Buddy. Studying: true'
// console.log(Object.getPrototypeOf(me) === coder); // true
// console.log(me.hasOwnProperty('name')); // true ← own property
// console.log(me.hasOwnProperty('introduction')); // false ← inherited from coder
// ============================================================
// 7. Object.seal() [ES5 | 2009]
// ============================================================
/*
Seals an object — no new properties can be added,
no existing properties can be deleted.
BUT existing property values CAN still be modified.
Interview note:
- Object.isSealed(obj) to check if sealed
- Sealed objects are extensible: false + configurable: false
- Does NOT affect nested objects (shallow seal)
- Difference from freeze: seal allows modification, freeze does not
*/
const sealedObj = { name: 'Buddy', age: 22 };
Object.seal(sealedObj);
sealedObj.name = 'John'; // ✅ allowed — modification
sealedObj.gender = 'male'; // ❌ silently ignored (not added)
delete sealedObj.age; // ❌ silently ignored (not deleted)
// console.log(sealedObj); // { name: 'John', age: 22 }
// console.log(Object.isSealed(sealedObj)); // true
// ============================================================
// 8. Object.freeze() [ES5 | 2009]
// ============================================================
/*
Completely freezes an object — no add, delete, or modify allowed.
Makes the object fully immutable (at the top level).
Interview note:
- Object.isFrozen(obj) to check if frozen
- Shallow freeze only — nested objects are NOT frozen!
- For deep freeze, need a recursive custom function
- Frozen objects are: extensible: false + configurable: false + writable: false
- Use for constants, config objects you don't want mutated
*/
const frozenObj = { name: 'Buddy', age: 22 };
Object.freeze(frozenObj);
frozenObj.name = 'John'; // ❌ silently ignored
frozenObj.gender = 'male'; // ❌ silently ignored
delete frozenObj.age; // ❌ silently ignored
// console.log(frozenObj); // { name: 'Buddy', age: 22 } ← untouched
// console.log(Object.isFrozen(frozenObj)); // true
// Shallow freeze trap ⚠️
const config = Object.freeze({ db: { host: 'localhost' } });
config.db.host = 'production'; // ❌ nested NOT frozen!
// console.log(config.db.host); // 'production' ← changed!
// Deep freeze (custom utility)
function deepFreeze(obj) {
Object.keys(obj).forEach(key => {
if (typeof obj[key] === 'object' && obj[key] !== null) deepFreeze(obj[key]);
});
return Object.freeze(obj);
}
// ============================================================
// 9. Object.hasOwn() [ES13 | 2022]
// ============================================================
/*
Checks if an object has a specific property as its OWN (not inherited).
Safer and cleaner replacement for hasOwnProperty().
Interview note:
- hasOwnProperty() can be overridden or fail on Object.create(null) objects
- Object.hasOwn() works even on objects with no prototype
- Always prefer Object.hasOwn() in modern code
*/
const user = { name: 'Alice', age: 25 };
// Old way — can be overridden or break on null-prototype objects
// console.log(user.hasOwnProperty('name')); // true
// console.log(user.hasOwnProperty('toString')); // false
// New way ✨ — static method, always safe
// console.log(Object.hasOwn(user, 'name')); // true
// console.log(Object.hasOwn(user, 'toString')); // false ← inherited, not own
// console.log(Object.hasOwn(user, 'address')); // false ← doesn't exist
// Why hasOwnProperty() can fail ⚠️
const nullProto = Object.create(null);
nullProto.name = 'test';
// nullProto.hasOwnProperty('name'); // ❌ TypeError — no prototype!
// console.log(Object.hasOwn(nullProto, 'name')); // ✅ true ← always works
// ============================================================
// 10. Object Destructuring [ES6 | 2015]
// ============================================================
/*
Extracts properties from an object into individual variables.
Cleaner alternative to accessing properties one by one.
Interview note:
- Can rename while destructuring
- Can set default values if property is undefined
- Works in function parameters directly
- Nested destructuring supported
*/
const car = { model: 'BMW', engine: 'V8', color: 'Black' };
// Basic destructuring
const { model, engine, color } = car;
// console.log(model); // 'BMW'
// console.log(engine); // 'V8'
// Rename while destructuring
const { model: carModel, color: carColor } = car;
// console.log(carModel); // 'BMW'
// Default values — used when property is undefined
const { model: m, year = 2024 } = car;
// console.log(year); // 2024 ← default used since car.year is undefined
// Nested destructuring
const person = { name: 'Alice', address: { city: 'NYC', zip: '10001' } };
const { name, address: { city, zip } } = person;
// console.log(city); // 'NYC'
// console.log(zip); // '10001'
// In function parameters ✨
function displayUser({ name, age = 18, role = 'Guest' }) {
return `${name} | Age: ${age} | Role: ${role}`;
}
// console.log(displayUser({ name: 'Bob', age: 25 })); // 'Bob | Age: 25 | Role: Guest'
// ============================================================
// 11. Object.getPrototypeOf() [ES5 | 2009]
// ============================================================
/*
Returns the prototype (internal [[Prototype]]) of an object.
Safer than accessing __proto__ directly.
Interview note:
- Use instead of obj.__proto__ (deprecated in strict environments)
- Returns null for objects created with Object.create(null)
*/
// console.log(Object.getPrototypeOf(me) === coder); // true
// console.log(Object.getPrototypeOf(user) === Object.prototype); // true
// console.log(Object.getPrototypeOf(Object.prototype)); // null ← end of chain
// ============================================================
// 12. Object.defineProperty() [ES5 | 2009]
// ============================================================
/*
Defines or modifies a property on an object with full control
over its behavior using a property descriptor.
Interview note:
- writable: can value be changed?
- enumerable: shows in loops / Object.keys()?
- configurable: can property be deleted or redefined?
- This is how Vue 2 / older libraries built reactivity!
*/
const profile = {};
Object.defineProperty(profile, 'id', {
value: 101,
writable: false, // cannot be changed
enumerable: false, // won't show in Object.keys()
configurable: false // cannot be deleted or redefined
});
// console.log(profile.id); // 101
profile.id = 999; // ❌ silently fails (not writable)
// console.log(profile.id); // 101 ← unchanged
// console.log(Object.keys(profile)); // [] ← not enumerable, hidden!
// ============================================================
// 13. Object.getOwnPropertyNames() [ES5 | 2009]
// ============================================================
/*
Returns ALL own property names — including non-enumerable ones.
Unlike Object.keys() which skips non-enumerable properties.
Interview note:
- Does NOT include Symbol keys (use Object.getOwnPropertySymbols() for that)
- Useful for debugging or inspecting hidden properties
*/
// console.log(Object.keys(profile)); // [] ← skips non-enumerable
// console.log(Object.getOwnPropertyNames(profile)); // ['id'] ← includes all
// ============================================================
// QUICK REFERENCE CHEAT SHEET
// ============================================================
// METHOD VERSION WHAT IT DOES
// ──────────────────────────────────────────────────────────────────
// Object.keys(obj) ES5 Own enumerable keys → array
// Object.values(obj) ES8 Own enumerable values → array
// Object.entries(obj) ES8 Own [key,value] pairs → array
// Object.fromEntries(arr) ES10 [key,value] pairs → object
// Object.assign(target, src) ES6 Merge/copy properties (shallow)
// Object.create(proto) ES5 New object with given prototype
// Object.seal(obj) ES5 Block add/delete, allow modify
// Object.freeze(obj) ES5 Block add/delete/modify (shallow)
// Object.hasOwn(obj, key) ES13 Safe own property check ✨
// Object.defineProperty() ES5 Define property with descriptor
// Object.getPrototypeOf(obj) ES5 Get prototype of object
// Object.getOwnPropertyNames() ES5 All own keys (incl. non-enumerable)
// SEAL vs FREEZE (interview classic!)
// ──────────────────────────────────────────────────────────────────
// Object.seal() → can MODIFY existing | cannot ADD or DELETE
// Object.freeze() → cannot MODIFY | cannot ADD or DELETE
// CLONING QUICK REF
// ──────────────────────────────────────────────────────────────────
// Shallow: { ...obj } or Object.assign({}, obj)
// Deep: structuredClone(obj) [ES2022]
// Deep old: JSON.parse(JSON.stringify(obj)) ← loses functions!