Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cloneDeep maintains reference after cloning? #2725

Closed
hulbert opened this issue Oct 11, 2016 · 6 comments
Closed

cloneDeep maintains reference after cloning? #2725

hulbert opened this issue Oct 11, 2016 · 6 comments
Labels

Comments

@hulbert
Copy link

hulbert commented Oct 11, 2016

Not sure if this is intended, it doesn't match what I use _.cloneDeep for but perhaps it's desired for other cases. It came up unexpectedly in our codebase so I'd be curious—if it's intended behavior—if it could be documented clearly.

It seems that _.cloneDeep maintains, in the cloned object, two keys referencing the same object in the original object.

Example case:

'use strict'

let _ = require('lodash')

let x = { lodash: 'isgreat' }

let y = { 
    one: x,
    two: x,
    three: { 
        javascript: 'isfun' 
    }
}

console.log('One and two are equal in original object?', y.one === y.two)

let yy = _.cloneDeep(y)

console.log('One and two are equal in deep cloned object?', yy.one === yy.two)
console.log('One is different object before and after clone?', y.one === yy.one)

This prints:

One and two are equal in original object? true
One and two are equal in deep cloned object? true
One is different object before and after clone? false

I would have expected it to print:

One and two are equal in original object? true
One and two are equal in deep cloned object? false
One is different object before and after clone? false

@jdalton
Copy link
Member

jdalton commented Oct 11, 2016

Hi @hulbert!

Our _.cloneDeep method supports circular references. So

y.one === y.two // true
yy.one === y.one // false
yy.one === yy.two // true

@jdalton jdalton closed this as completed Oct 11, 2016
@hulbert
Copy link
Author

hulbert commented Oct 11, 2016

@jdalton would you accept a PR to better document this behavior?

Additionally, is there a way to deep clone without this behavior in lodash. The use case is a large object/document that may need to be mutated but has some duplicate values via reference to avoid repetition and clarify that they're the same. In our case, a large deeply nested settings object for configuring a job.

@jdalton
Copy link
Member

jdalton commented Oct 12, 2016

The clone behavior is glossed over as "This method is loosely based on the structured clone algorithm". See http://w3c.github.io/html/infrastructure.html#section-structuredclonewithtransfer

The purpose of the memory map, both here and in the StructuredClone abstract operation, is to avoid cloning objects twice. This ends up preserving cycles and the identity of duplicate objects in graphs.

You might be able to customize the cloning behavior with _.cloneDeepWith.

@iabw
Copy link

iabw commented Sep 13, 2017

I would also vote for it to be better documented that this is the case.

Especially since many sources

inadequately or incompletely explain lodash's clone:

incorrectly equate it with jQuery's deep extend:

or don't mention lodash at all, when it would be worth a footnote:

I think the only mention of this behavior that I've managed to find is this issue. Even the link to MDN in _.clone's description only says recursing through the input object while maintaining a map of previously visited references, which might be argued is not explicit enough about what is actually included in the final result.

Just adding a minimal repro to the examples for _.clone and _.cloneDeep (like the one @hulbert included above) would probably save some headaches.

@vhf
Copy link

vhf commented Oct 23, 2017

Agreed, an answer to this:

@jdalton would you accept a PR to better document this behavior?

would be welcome. 👍

@lodash lodash deleted a comment from rodrigogs Oct 30, 2017
@lock
Copy link

lock bot commented Dec 26, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Dec 26, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

No branches or pull requests

4 participants