https://bigfrontend.dev/problem/implement-object-assign
The Object.assign() method copies all enumerable own properties from one or more source objects to a target object. It returns the target object. (source: MDN)
It is widely used, Object Spread operator actually is internally the same as Object.assign() (source). Following 2 lines of code are totally the same.
let aClone = { ...a };
let aClone = Object.assign({}, a);This is an easy one, could you implement Object.assign() with your own implementation?
/**
* @param {any} target
* @param {any[]} sources
* @return {object}
*/
function objectAssign(target, ...sources) {
if (!target) {
throw new Error();
}
if (typeof target !== 'object') {
const constructor = Object.getPrototypeOf(target).constructor;
target = new constructor(target);
}
for (const source of sources) {
if (!source) {
continue;
}
const keys = [
...Object.keys(source),
...Object.getOwnPropertySymbols(source),
];
for (const key of keys) {
const descriptor = Object.getOwnPropertyDescriptor(target, key);
if (descriptor && !descriptor.configurable) {
throw new Error();
}
target[key] = source[key];
}
}
return target;
}const obj = { a: 1 };
const copy = objectAssign({}, obj);
console.log(copy); // { a: 1 }
console.log(copy === obj); // false
console.log(Object.getPrototypeOf(copy) === Object.getPrototypeOf(obj)); // true
console.log(Object.getOwnPropertyDescriptor(copy, "a")); // { value: 1, writable: true, enumerable: true, configurable: true }
console.log(Object.getOwnPropertyDescriptor(obj, "a")); // { value: 1, writable: true, enumerable: true, configurable: true }
console.log(Object.getOwnPropertyDescriptor(copy, "b")); // undefined
console.log(Object.getOwnPropertyDescriptor(obj, "b")); // undefinedLet's break down the objectAssign function and its usage:
-
Function Definition: The
objectAssignfunction is defined to take atargetobject and any number ofsourcesobjects. It's designed to mimic the behavior of the built-inObject.assignmethod in JavaScript. -
Error Checking: If
targetis not provided or isnull, it throws an error. Iftargetis not an object, it creates a new instance oftarget's prototype's constructor and assigns it totarget. -
Iterating Over Sources: It then iterates over each
sourceinsources. If asourceis not provided or isnull, it skips to the nextsource. -
Getting Keys: For each
source, it gets an array of its own enumerable property keys and symbols. -
Copying Properties: It then iterates over each key in
keys. Iftargethas a non-configurable own property with the same key, it throws an error. Otherwise, it assigns the value of thesourceproperty to thetargetproperty. -
Return Value: After all
sourceshave been processed, it returnstarget. -
Usage: The function is then used to create a shallow copy of an object
obj. The copy is logged to the console, showing that it has the same properties asobj. It also logs thatcopyis not the same object asobj, that they have the same prototype, and that they have the same property descriptors for "a" and no property descriptor for "b".
This objectAssign function provides a way to copy properties from one or more source objects to a target object. It throws an error if the target object is not provided or if a non-configurable property of the target object would be overwritten.
Here are some real-world examples of how Object.assign can be used:
const userBasicInfo = {
name: 'John Doe',
age: 30
};
const userContactInfo = {
email: 'john.doe@example.com',
phone: '123-456-7890'
};
const userProfile = Object.assign({}, userBasicInfo, userContactInfo);
console.log(userProfile);
// Output: { name: 'John Doe', age: 30, email: 'john.doe@example.com', phone: '123-456-7890' }const originalObject = {
name: 'Jane Smith',
profession: 'Software Developer'
};
const clonedObject = Object.assign({}, originalObject);
clonedObject.profession = 'Senior Software Developer';
console.log(originalObject.profession); // Output: 'Software Developer'
console.log(clonedObject.profession); // Output: 'Senior Software Developer'const defaultSettings = {
theme: 'dark',
showNotifications: true,
sounds: true
};
const userSettings = {
theme: 'light',
sounds: false
};
const finalSettings = Object.assign({}, defaultSettings, userSettings);
console.log(finalSettings);
// Output: { theme: 'light', showNotifications: true, sounds: false }function deepMerge(target, source) {
for (const key of Object.keys(source)) {
if (source[key] instanceof Object && key in target) {
Object.assign(source[key], deepMerge(target[key], source[key]));
}
}
Object.assign(target || {}, source);
return target;
}
const config1 = {
database: {
host: 'localhost',
port: 3306
},
server: {
port: 8000
}
};
const config2 = {
database: {
port: 5432,
username: 'admin'
},
server: {
host: '127.0.0.1'
}
};
const finalConfig = deepMerge(config1, config2);
console.log(finalConfig);
// Output:
// {
// database: { host: 'localhost', port: 5432, username: 'admin' },
// server: { port: 8000, host: '127.0.0.1' }
// }const canEat = {
eat() {
console.log('Eating...');
}
};
const canWalk = {
walk() {
console.log('Walking...');
}
};
const person = Object.assign({}, canEat, canWalk);
person.eat(); // Output: 'Eating...'
person.walk(); // Output: 'Walking...'These examples demonstrate practical uses of Object.assign in various real-world scenarios, highlighting its versatility in handling object manipulation tasks in JavaScript.