mergeDeep.js 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. import { isSome } from './helpers.js';
  2. export function mergeDeep(sources, respectPrototype = false) {
  3. const target = sources[0] || {};
  4. const output = {};
  5. if (respectPrototype) {
  6. Object.setPrototypeOf(output, Object.create(Object.getPrototypeOf(target)));
  7. }
  8. for (const source of sources) {
  9. if (isObject(target) && isObject(source)) {
  10. if (respectPrototype) {
  11. const outputPrototype = Object.getPrototypeOf(output);
  12. const sourcePrototype = Object.getPrototypeOf(source);
  13. if (sourcePrototype) {
  14. for (const key of Object.getOwnPropertyNames(sourcePrototype)) {
  15. const descriptor = Object.getOwnPropertyDescriptor(sourcePrototype, key);
  16. if (isSome(descriptor)) {
  17. Object.defineProperty(outputPrototype, key, descriptor);
  18. }
  19. }
  20. }
  21. }
  22. for (const key in source) {
  23. if (isObject(source[key])) {
  24. if (!(key in output)) {
  25. Object.assign(output, { [key]: source[key] });
  26. }
  27. else {
  28. output[key] = mergeDeep([output[key], source[key]], respectPrototype);
  29. }
  30. }
  31. else {
  32. Object.assign(output, { [key]: source[key] });
  33. }
  34. }
  35. }
  36. }
  37. return output;
  38. }
  39. function isObject(item) {
  40. return item && typeof item === 'object' && !Array.isArray(item);
  41. }