-
Notifications
You must be signed in to change notification settings - Fork 775
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(utils/clone): don't try to clone elements from different window c…
…ontext (#4072) * fix(utils/clone): don't try to clone elements from different window context * weakmap * don't use cache between calls * use strict equal * use strict equal * cache * create on internal * typo
- Loading branch information
Showing
2 changed files
with
120 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,47 @@ | ||
/** | ||
* Deeply clones an object or array | ||
* Deeply clones an object or array. DOM nodes or collections of DOM nodes are not deeply cloned and are instead returned as is. | ||
* @param {Mixed} obj The object/array to clone | ||
* @return {Mixed} A clone of the initial object or array | ||
* @return {Mixed} A clone of the initial object or array | ||
*/ | ||
function clone(obj) { | ||
/* eslint guard-for-in: 0*/ | ||
var index, | ||
length, | ||
out = obj; | ||
// DOM nodes cannot be cloned. | ||
export default function clone(obj) { | ||
return cloneRecused(obj, new Map()); | ||
} | ||
|
||
// internal function to hide non-user facing parameters | ||
function cloneRecused(obj, seen) { | ||
if (obj === null || typeof obj !== 'object') { | ||
return obj; | ||
} | ||
|
||
// don't clone DOM nodes. since we can pass nodes from different window contexts | ||
// we'll also use duck typing to determine what is a DOM node | ||
if ( | ||
(window?.Node && obj instanceof window.Node) || | ||
(window?.HTMLCollection && obj instanceof window.HTMLCollection) | ||
(window?.HTMLCollection && obj instanceof window.HTMLCollection) || | ||
('nodeName' in obj && 'nodeType' in obj && 'ownerDocument' in obj) | ||
) { | ||
return obj; | ||
} | ||
|
||
if (obj !== null && typeof obj === 'object') { | ||
if (Array.isArray(obj)) { | ||
out = []; | ||
for (index = 0, length = obj.length; index < length; index++) { | ||
out[index] = clone(obj[index]); | ||
} | ||
} else { | ||
out = {}; | ||
for (index in obj) { | ||
out[index] = clone(obj[index]); | ||
} | ||
} | ||
// handle circular references by caching the cloned object and returning it | ||
if (seen.has(obj)) { | ||
return seen.get(obj); | ||
} | ||
|
||
if (Array.isArray(obj)) { | ||
const out = []; | ||
seen.set(obj, out); | ||
obj.forEach(value => { | ||
out.push(cloneRecused(value, seen)); | ||
}); | ||
return out; | ||
} | ||
|
||
const out = {}; | ||
seen.set(obj, out); | ||
// eslint-disable-next-line guard-for-in | ||
for (const key in obj) { | ||
out[key] = cloneRecused(obj[key], seen); | ||
} | ||
return out; | ||
} | ||
|
||
export default clone; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters