Skip to content

Instantly share code, notes, and snippets.

@dSalieri
Last active February 22, 2023 02:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dSalieri/97ae068448d7e9618f47dc5e2955ebea to your computer and use it in GitHub Desktop.
Save dSalieri/97ae068448d7e9618f47dc5e2955ebea to your computer and use it in GitHub Desktop.
Реализация вложенного Object.assign

Цель: Реализация вложенного присваивания, алгоритм основывается на алгоритме из спецификации Object.assign ECMAScript.

/// Демонстрация
const a = {
  a: 1, 
  b: 2, 
  c: 3, 
  obj: {
    aa: 11, 
    bb: 22, 
    cc: 33
  }
};
const b = {
  c: "3c",  
  obj: {
    cc: "33cc",
    dd: "44dd",
  }
};
deepAssign({}, a, b); /// {a: 1, b: 2, c: "3c", obj: {aa: 11, bb: 22, cc: "33cc", dd: "44dd"}}

Замечание: Данный алгоритм как и Object.assign не создает копии объектов у свойств, поэтому когда вы передаете объект для слияния у которого свойства могут быть объектами, то результирующее свойство будет ссылаться на один и тот же объект.

const a = {a: 1, b: 2, c: 3};
const b = {a: 1, b: 2, c: {value: 3}};

Object.assign(a, b);
a.c === b.c /// true


Вывод: Сливаемые объекты должны быть скопированы, чтобы по ошибке не изменить важный объект, который использовался в объединении.

function deepAssign (target, ...sources) {
const collection = new Set();
return (function assign(target, ...sources) {
let to = Object(target);
collection.add(to);
if (arguments.length === 1) return to;
for (const nextSource of sources) {
if (nextSource != null) {
let from = Object(nextSource);
let keys = Reflect.ownKeys(from);
for (const nextKey of keys) {
let desc = Reflect.getOwnPropertyDescriptor(from, nextKey);
if (desc !== undefined && desc.enumerable === true) {
let propValue = Reflect.get(from, nextKey);
/// This condition works with nested properties, its definition determine how nested properties will be recorded
if (typeof propValue === "object" && propValue !== null && typeof to[nextKey] === "object" && to[nextKey] !== null && !collection.has(to[nextKey])) {
propValue = assign({}, to[nextKey], propValue);
}
Reflect.set(to, nextKey, propValue);
}
}
}
collection.clear();
}
return to;
})(target, ...sources);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment