DEV Community

Bukunmi Odugbesan
Bukunmi Odugbesan

Posted on

Coding Challenge Practice - Question 102

The task is to implement _.cloneDeep.

The boilerplate code

function cloneDeep(data) {
  // your code here
}
Enter fullscreen mode Exit fullscreen mode

cloneDeep is used for recursive deep copy. For primitive types, they are immutable, so they are returned as is

if(data === null || typeof data !== "object") {
return data;
}
Enter fullscreen mode Exit fullscreen mode

For circular references, WeakMap cannot be cloned

if (seen.has(data)) {
    return seen.get(data);
  }
Enter fullscreen mode Exit fullscreen mode

Special objects are handled explicitly because naive recursion breaks them. Dates need timestamp copy

if (data instanceof Date) {
    return new Date(data.getTime());
  }
Enter fullscreen mode Exit fullscreen mode

RegExp needs patterns and flags

if (data instanceof RegExp) {
    return new RegExp(data.source, data.flags);
  }
Enter fullscreen mode Exit fullscreen mode

Map needs to have their keys and values deep-cloned

if (data instanceof Map) {
    const result = new Map();
    seen.set(data, result);
    data.forEach((value, key) => {
      result.set(cloneDeep(key, seen), cloneDeep(value, seen));
    });
    return result;
  }
Enter fullscreen mode Exit fullscreen mode

Set values also need to be deep cloned

if (data instanceof Set) {
    const result = new Set();
    seen.set(data, result);
    data.forEach(value => {
      result.add(cloneDeep(value, seen));
    });
    return result;
  }
Enter fullscreen mode Exit fullscreen mode

For Arrays and Objects, preserve custom prototypes and class instances

 const result = Array.isArray(data)
    ? []
    : Object.create(Object.getPrototypeOf(data));

  seen.set(data, result);

  for (const key of Reflect.ownKeys(data)) {
    result[key] = cloneDeep(data[key], seen);
  }

  return result;
Enter fullscreen mode Exit fullscreen mode

The final code

function cloneDeep(data, seen = new WeakMap()) {
  // your code here
  if(data === null || typeof data !== "object") {
    return data;
  }

  if(seen.has(data)) {
    return seen.get(data);
  }

  if(data instanceof Date) {
    return new Date(data.getTime());
  }

  if(data instanceof RegExp) {
    return new RegExp(data.source, data.flags);
  }

  if(data instanceof Map) {
    const result = new Map();
    seen.set(data, result);
    data.forEach((value, key) => {
      result.set(cloneDeep(key, seen), cloneDeep(value, seen));
    })
    return result;
  }

  if(data instanceof Set) {
    const result = new Set();
    seen.set(data, result);
    data.forEach(value => {
      result.add(cloneDeep(value, seen));
    })
    return result;
  }
  const result = Array.isArray(data) ? [] : Object.create(Object.getPrototypeOf(data));
  seen.set(data, result);

  for(const key of Reflect.ownKeys(data)) {
    result[key] = cloneDeep(data[key], seen);
  }
  return result;
}
Enter fullscreen mode Exit fullscreen mode

That's all folks!

Top comments (0)