I'm having trouble understanding when a data assignment to an object is a reference and when a copy of the object is created. I thought I understood but the following example doesn't fit my simple undestanding of it.
An event handler starts off a series of steps as follows.
Promise.allSettled( [ gather_write, get_build ] ).then( test );
Promises gather_write and get_build perform unrelated functions. The first gathers some data from the DOM and writes it to the database. The second retrieves data from the database and builds a document fragment. If both fulfill, then a node in the DOM is replaced with the fragment.
It's too much code to show here, but get_build, after successfully getting the data from the database, invokes a separate function that builds the document fragment, and was returning its result as a property of the resolve object. That worked fine; and then I wanted to try to provide options to the user in the event that gather_write rejected and get_build fulfilled, which requires the temporary storing of the document fragment. So, instead of returning it and passing it back to the Promise.allSettled, it is stored in a property of the function that builds it.
In the synchronous function build the code is set up as:
function build()
{
let f;
try
{
f = document.createFragment();
// ...build the fragment...
build.html = f;
}
catch(e)
{ }
finally
{ f = null; }
} // close build
Function build has to complete before the promise get_build can resolve, after which the Promise.allSettled can be evaluated; and, if both promises fulfill, the function to replace the DOM node with the newly built fragment stored in build.html can be invoked. I thought that build.html would be a reference to the node object f and that, since f is set to null in the finally block, that would take place before all the above could complete, and when the code to use build.html was finally run it would be pointing to a null rather than the fragment. So, the assignment statement should be build.html = f.cloneNode(true).
However, the process works fine with and without using f.cloneNode. Would you please explain why? I don't want the browser to take the steps to clone the fragment if it is unnecessary, but hesitate to exclude it without understanding why it is working without cloning.
Thank you.
You can think of every variable name as a pointer to a memory location. Setting a variable name to
nulldoes not alter anything in what the variable used to contain; all it does is change what the variable name points to, from the prior reference (here, to a document fragment) to the new reference (null). So, when you dothen, no matter if/how the
fvariable name gets reassigned in the future,build.htmlwill not be altered, because it continues to point to the document fragment. The only way thebuild.htmlwould be altered would be if the fragment was mutated (such as assigning to a property offbefore the reassignment, or calling one of the fragment's methods).Here's another minimal example of this behavior:
Again, here, although
fgets set tonull, the object{ prop: 'val' }remains intact and unmutated, sofoo.fgets a reference to that object, and continues to hold that reference even afterfgets reassigned.With your code, since the fragment in memory remains in memory, and the
build.htmlretains a reference to that fragment even afterfgets reassigned, cloning the fragment is just unnecessary overhead; feel free to leave it out.Another way to visualize it is that your code:
is equivalent to