Skip to content

Commit

Permalink
feat: try native structuredClone in cloneDeep
Browse files Browse the repository at this point in the history
resolves lodash#5833
  • Loading branch information
lewxdev committed Apr 29, 2024
1 parent a67a085 commit f99b003
Show file tree
Hide file tree
Showing 3 changed files with 674 additions and 654 deletions.
27 changes: 24 additions & 3 deletions src/cloneDeep.ts
Expand Up @@ -6,11 +6,18 @@ const CLONE_SYMBOLS_FLAG = 4;

/**
* This method is like `clone` except that it recursively clones `value`.
* Object inheritance is preserved.
* Object inheritance is preserved. The method will attempt to use the native
* [`structuredClone`](https://developer.mozilla.org/docs/Web/API/structuredClone)
* function, if `value` [is supported](https://developer.mozilla.org/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types)
* (and the native implementation is available). Otherwise it will fallback to a
* custom implementation.
*
* @since 1.0.0
* @category Lang
* @param {*} value The value to recursively clone.
* @param {boolean} [skipNativeCheck]
* Skip the native check and use the custom implementation. This is useful when
* `value` is known to be incompatible `structuredClone`.
* @returns {*} Returns the deep cloned value.
* @see clone
* @example
Expand All @@ -20,9 +27,23 @@ const CLONE_SYMBOLS_FLAG = 4;
* const deep = cloneDeep(objects)
* console.log(deep[0] === objects[0])
* // => false
*
* // The `skipNativeCheck` flag
* const unsupportedNativeObject = { fn: () => 'a' };
*
* const deep = cloneDeep(unsupportedNativeObject, true);
* console.log(deep === unsupportedNativeObject);
* // => false
*/
function cloneDeep(value) {
return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
function cloneDeep(value, skipNativeCheck) {
try {
if (!skipNativeCheck && structuredClone) {
return structuredClone(value);
}
throw new Error('Unsupported structured clone');
} catch {
return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
}
}

export default cloneDeep;
10 changes: 9 additions & 1 deletion test/clone-methods.spec.js
Expand Up @@ -28,7 +28,7 @@ import cloneDeep from '../src/cloneDeep';
import cloneDeepWith from '../src/cloneDeepWith';
import last from '../src/last';

xdescribe('clone methods', function () {
describe('clone methods', function () {
function Foo() {
this.a = 1;
}
Expand Down Expand Up @@ -117,6 +117,14 @@ xdescribe('clone methods', function () {
assert.notStrictEqual(actual, cyclical[`v${LARGE_ARRAY_SIZE - 1}`]);
});

it('`_.cloneDeep` should accept the `skipNativeCheck` flag', () => {
const object = { primitive: "a", fn: () => "b" };
const actual = cloneDeep(object, true);

expect(actual).not.toEqual(object);
expect(actual.primitive).not.toEqual(object.primitive);
});

it('`_.cloneDeepWith` should provide `stack` to `customizer`', () => {
let actual;

Expand Down

0 comments on commit f99b003

Please sign in to comment.