Object.assign Polyfill
ObjectsPolyfill
Implement Object.myAssign(target, ...sources).
Requirements:
- Throw
TypeErroriftargetis null or undefined - Skip null/undefined sources silently
- Copy own enumerable properties — both string keys and symbol keys
- Mutate and return the target
- This is a shallow copy — nested objects are copied by reference
Examples
Example 1
Input
Object.myAssign({ a: 1 }, { b: 2 }, { c: 3 })Output
{ a: 1, b: 2, c: 3 }Explanation
Properties from all sources are merged into the target.
Example 2
Input
const sym = Symbol('x');
Object.myAssign({}, { [sym]: 42 })Output
{ [Symbol(x)]: 42 }Explanation
Symbol keys are copied — use Reflect.ownKeys, not Object.keys.
Constraints
- Use `Reflect.ownKeys` to capture symbol keys
- Check `descriptor.enumerable` before copying
Notes
- Later sources overwrite earlier ones for the same key
Hints
Editorial: Object.assign Polyfill
Implementing Object.assign from scratch
Object.assign copies own enumerable properties from one or more source objects onto a target, mutates it, and returns it. Later sources overwrite earlier ones.
What the interviewer checks
- Do you skip
null/undefinedsources without throwing? - Do you copy only own enumerable properties, not inherited ones?
- Do you copy symbol keys too? Most candidates miss this.
Implementation
Object.myAssign = function (target, ...sources) { if (target === null || target === undefined) { throw new TypeError("Cannot convert undefined or null to object"); } const to = Object(target); for (const source of sources) { if (source === null || source === undefined) continue; const from = Object(source); // Reflect.ownKeys gets string keys AND symbol keys for (const key of Reflect.ownKeys(from)) { const descriptor = Object.getOwnPropertyDescriptor(from, key); if (descriptor && descriptor.enumerable) { to[key] = from[key]; } } } return to; };
Why Reflect.ownKeys instead of Object.keys
Object.keys returns only own enumerable string keys.
Reflect.ownKeys returns own enumerable and non-enumerable string and symbol keys.
After getting all keys, we still check descriptor.enumerable to skip non-enumerable ones.
const sym = Symbol("x"); const source = { a: 1, [sym]: 2 }; Object.keys(source); // ["a"] — sym is missing Reflect.ownKeys(source); // ["a", sym] — both present
Shallow copy caveat
Nested objects are copied by reference, not cloned:
const source = { nested: { x: 1 } }; const target = Object.myAssign({}, source); target.nested === source.nested; // true — same reference target.nested.x = 99; // mutates source.nested too
Always mention this in an interview — it distinguishes assign from a deep clone.
Edge cases to mention
targetisnull/undefined→ throwsTypeError- Sources that are
null/undefined→ silently skipped - Prototype-inherited properties are not copied
- Non-enumerable properties are not copied
- Symbol-keyed properties are copied (via
Reflect.ownKeys)
</>JavaScript
Loading editor…
Test Result
Run your code, or Submit to test it