Skip to content

Conversation

@zargold
Copy link

@zargold zargold commented Mar 15, 2021

Supports _.cloneDeep as discussed in Issue: #121.

  • Tests written
  • Documentation updated
  • added support per Object.fromEntries on MDN.

Copy link

@VitorLuizC VitorLuizC left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would break if we pass null.

Raz Goldin and others added 2 commits March 15, 2021 16:51
Co-authored-by: Vitor Luiz Cavalcanti <[email protected]>
Co-authored-by: Vitor Luiz Cavalcanti <[email protected]>
@iandrewt
Copy link
Contributor

This breaks on an object with circular references

const object = {
  'bar': {},
  'foo': { 'b': { 'c': { 'd': {} } } },
};

object.foo.b.c.d = object;
object.bar.b = object.foo.b;

cloneDeep(object);
Uncaught RangeError: Maximum call stack size exceeded

@iandrewt
Copy link
Contributor

iandrewt commented Jul 7, 2021

Here's the cloneDeep function I'm using, courtesy of StackOverflow

function cloneDeep(obj, hash = new WeakMap()) {
  if (Object(obj) !== obj || obj instanceof Function) {
    return obj;
  }

  if (hash.has(obj)) {
    return hash.get(obj);
  }

  let result: any;

  try { // Try to run constructor without arguments
    result = new obj.constructor();
  } catch (e) {
    result = Object.create(Object.getPrototypeOf(obj));
  }

  if (obj instanceof Map) {
    Array.from(obj, ([key, val]) => result.set(cloneDeep(key, hash), cloneDeep(val, hash)));
  } else if (obj instanceof Set) {
    Array.from(obj, (key) => result.add(cloneDeep(key, hash)));
  }

  hash.set(obj, result);

  return Object.assign(result, ...Object.keys(obj).map(key => ({ [key]: cloneDeep(obj[key], hash) })));
};

@zargold
Copy link
Author

zargold commented Jul 7, 2021

Here's the cloneDeep function I'm using, courtesy of StackOverflow

function cloneDeep(obj, hash = new WeakMap()) {
  if (Object(obj) !== obj || obj instanceof Function) {
    return obj;
  }

  if (hash.has(obj)) {
    return hash.get(obj);
  }

  let result: any;

  try { // Try to run constructor without arguments
    result = new obj.constructor();
  } catch (e) {
    result = Object.create(Object.getPrototypeOf(obj));
  }

  if (obj instanceof Map) {
    Array.from(obj, ([key, val]) => result.set(cloneDeep(key, hash), cloneDeep(val, hash)));
  } else if (obj instanceof Set) {
    Array.from(obj, (key) => result.add(cloneDeep(key, hash)));
  }

  hash.set(obj, result);

  return Object.assign(result, ...Object.keys(obj).map(key => ({ [key]: cloneDeep(obj[key], hash) })));
};

Yes, an unusual use case so I didn't adapt for it.

Just in case we want to support that: recursiveCloneWithCircularReference it would be easy:

const recursiveClone = (src, hash = new WeakMap()) => {

      if (src === null || typeof src !== 'object') { // for primitives / functions / non-references/pointers
        return src
      }
     if (hash.has(obj)) {
        return hash.get(obj);
      }
     let result;
      if (Array.isArray(src)) { // for arrays
        result = src.map(element => recursiveClone(element, hash))
      }
      result = Object.fromEntries(
        Object.entries(src).map(
          ([key, val]) => ([key, recursiveClone(val, hash)])
        )
      )
      hash.set(src, result);
      return result;
    }

In case we also want to support things like Maps & Sets we could too.

@iandrewt
Copy link
Contributor

iandrewt commented Jul 7, 2021

Unfortunately the project I was working on did need all the edge cases, but I'm glad there's a good simplified version

@stevemao stevemao requested a review from a team January 13, 2022 04:22
@kingyue737
Copy link
Contributor

Is structuredClone equal to deepClone?
https://developer.mozilla.org/en-US/docs/Web/API/structuredClone

@zargold
Copy link
Author

zargold commented Apr 8, 2022

Is structuredClone equal to deepClone?
https://developer.mozilla.org/en-US/docs/Web/API/structuredClone

Awesome find. I think people may complain that it lacks support for functions, but I don't often see the need for that piece of functionality.

@cht8687 cht8687 force-pushed the master branch 2 times, most recently from 5559a1c to bd9b25e Compare September 2, 2023 04:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants