clone-deep.js 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. /**
  2. * Clone deep.
  3. *
  4. * @author https://stackoverflow.com/a/4460624
  5. * @param {*} value
  6. * @returns {*}
  7. */
  8. export function cloneDeep(value) {
  9. if (!value) return value; // null, undefined values check
  10. const types = [Number, String, Boolean];
  11. let result;
  12. // normalizing primitives if someone did new String('aaa'),
  13. // or new Number('444');
  14. types.forEach(type => {
  15. if (value instanceof type) result = type(value);
  16. });
  17. if (result === undefined) {
  18. if (Array.isArray(value)) {
  19. result = [];
  20. value.forEach((child, index) => {
  21. result[index] = cloneDeep(child);
  22. });
  23. } else if (typeof value === 'object') {
  24. // testing that this is DOM
  25. if (
  26. 'nodeType' in value &&
  27. value.nodeType &&
  28. 'cloneNode' in value &&
  29. typeof value.cloneNode === 'function'
  30. ) {
  31. result = value.cloneNode(true);
  32. // check that this is a literal
  33. } else if (!('prototype' in value) || !value.prototype) {
  34. if (value instanceof Date) {
  35. result = new Date(value);
  36. } else if (value.constructor && value.constructor.name === 'Object') {
  37. // it is an object literal
  38. result = {};
  39. for (const key in value) {
  40. result[key] = cloneDeep(value[key]);
  41. }
  42. } else {
  43. // just keep the reference,
  44. // or create new object
  45. result = value;
  46. }
  47. } else {
  48. // just keep the reference,
  49. // or create new object
  50. result = value;
  51. }
  52. } else {
  53. result = value;
  54. }
  55. }
  56. return result;
  57. }