Toggle navigation
MeasureThat.net
Create a benchmark
Tools
Feedback
FAQ
Register
Log In
Run results for:
Lodash cloneDeep vs structuredClone vs node-clone no circular check, cloning of configs
https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
Go to the benchmark
Embed
Embed Benchmark Result
Run details:
User agent:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 YaBrowser/24.4.0.0 Safari/537.36
Browser:
Yandex Browser 24
Operating system:
Mac OS X 10.15.7
Device Platform:
Desktop
Date tested:
one year ago
Test name
Executions per second
Lodash cloneDeep
19246.3 Ops/sec
Native structuredClone
22212.0 Ops/sec
clone();
182.9 Ops/sec
_cloneDeep custom underscore/lodash
12063.9 Ops/sec
HTML Preparation code:
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js'></script>
Script Preparation code:
var MyObject = JSON.parse(`{ "status": 200, "message": "seConfig(210-2) last updated by user apiuser on 2020-09-25T03:52:14Z", "errors": [], "seConfig": { "id": 210, "name": "New configuration", "description": "Adding factor with tags amd removing use case tags ", "versionId": 2, "status": "DRAFT", "createdFromVersionId": 1, "importedFrom": null, "requirements": "", "numActiveUsers": 0, "numUsers": 0, "numAccounts": 0, "configCountryCode": "DEFAULT", "isReadOnly": false, "repTeamId": null, "isMasterConfig": false, "lastSyncTimestamp": null, "lastSyncHashCode": null, "lastSyncReport": null, "isSyncPending": false, "createdAt": "2020-09-25T03:50:15Z", "createdBy": "apiuser", "updatedAt": "2020-09-25T03:52:14Z", "updatedBy": "apiuser", "startedAt": null, "startedBy": null, "stoppedAt": null, "stoppedBy": null, "errors": [], "statusId": 0, "repTeam": { "name": null, "uid": null, "numReps": null }, "globalParameters": [ { "typeId": "GlobalParameters", "requirements": "", "name": "GlobalParameters", "description": "GlobalParameters", "availableProductsForFactors": "QA_a00U000000PunPcIA;QA_a00U000000PunPvIA;QA_a00U000000PunQ7IA;QA_a00U000000XL37cIA;AKT_ALL_PRODUCTS;a00g000000BoMJfAAN;a00g000000BoMKEAA3;a00g000000BoMKTAA3;PROD-01;PROD-02;PROD-03;PROD-04;PROD-05;PROD-06;QA_DSM00001pro;QA_DSM00002pro;Mentisan;Decloremaxo;Omparasol", "availableProductsForRules": "QA_a00U000000PunPcIA;QA_a00U000000PunPvIA;QA_a00U000000PunQ7IA;QA_a00U000000XL37cIA;AKT_ALL_PRODUCTS;a00g000000BoMJfAAN;a00g000000BoMKEAA3;a00g000000BoMKTAA3;PROD-01;PROD-02;PROD-03;PROD-04;PROD-05;PROD-06;QA_DSM00001pro;QA_DSM00002pro;Mentisan;Decloremaxo;Omparasol" } ], "localizationPropertyOverrides": {}, "messageStrategies": [], "segmentFactors": [], "factors": [ { "factorTypeId": "emailChannelFactor", "order": 1, "remEnabled": "false", "requirements": "", "isAnyRuleModified": false, "disabled": false, "suggestionTitleMVEL": null, "insightTitleMVEL": null, "enhancedInsightTitleMVEL": null, "segmentFactorIds": null, "segmentsGroupingCondition": "AND", "evaluationFrequency": "DAILY", "name": "Emails Channel", "description": "Factor that enables generation of token-based insights for suggested email channel actions", "reasonTemplates": [ { "tokenizedText": null, "crmFieldName": "", "destination": "Suggestion" }, { "tokenizedText": null, "crmFieldName": "", "destination": "Insight" }, { "tokenizedText": null, "crmFieldName": "", "destination": "EnhancedInsight" } ] }, { "factorTypeId": "visitChannelFactor", "order": 2, "remEnabled": "false", "requirements": "", "isAnyRuleModified": false, "disabled": false, "suggestionTitleMVEL": null, "insightTitleMVEL": null, "enhancedInsightTitleMVEL": null, "segmentFactorIds": null, "segmentsGroupingCondition": "AND", "evaluationFrequency": "DAILY", "name": "Visit Channel", "description": "Factor that enables generation of token-based insights for suggested visit actions", "reasonTemplates": [ { "tokenizedText": null, "crmFieldName": "", "destination": "Suggestion" }, { "tokenizedText": null, "crmFieldName": "", "destination": "Insight" }, { "tokenizedText": null, "crmFieldName": "", "destination": "EnhancedInsight" } ] }, { "factorTypeId": "webCallChannelFactor", "order": 3, "remEnabled": "false", "requirements": "", "isAnyRuleModified": false, "disabled": false, "suggestionTitleMVEL": null, "insightTitleMVEL": null, "enhancedInsightTitleMVEL": null, "segmentFactorIds": null, "segmentsGroupingCondition": "AND", "evaluationFrequency": "DAILY", "name": "Web Call Channel", "description": "Factor that enables generation of token-based insights for suggested web call actions", "reasonTemplates": [ { "tokenizedText": null, "crmFieldName": "", "destination": "Suggestion" }, { "tokenizedText": null, "crmFieldName": "", "destination": "Insight" }, { "tokenizedText": null, "crmFieldName": "", "destination": "EnhancedInsight" } ] }, { "factorTypeId": "suggestionReasonsFactor", "order": 4, "remEnabled": "false", "requirements": "", "isAnyRuleModified": false, "disabled": false, "suggestionTitleMVEL": null, "insightTitleMVEL": null, "enhancedInsightTitleMVEL": null, "segmentFactorIds": null, "segmentsGroupingCondition": "AND", "evaluationFrequency": "DAILY", "name": "Suggestion Reason Factor", "description": "Factor that enables generation of token-based insights for suggested visit actions", "reasonTemplates": [ { "tokenizedText": "", "crmFieldName": "", "destination": "Suggestion" }, { "tokenizedText": "", "crmFieldName": "", "destination": "Insight" }, { "tokenizedText": "", "crmFieldName": "", "destination": "EnhancedInsight" } ] }, { "factorTypeId": "pacingFactor", "order": 5, "id": "d5630ab4-3ade-cbb1-012a-1828eb079f1c", "masterFactorId": null, "excludedMasterFactorProductIds": "", "remEnabled": "false", "requirements": "", "isAnyRuleModified": false, "disabled": false, "suggestionTitleMVEL": null, "insightTitleMVEL": null, "enhancedInsightTitleMVEL": null, "segmentFactorIds": [], "segmentsGroupingCondition": "AND", "evaluationFrequency": "DAILY", "name": "New Pace & Priority Factor", "description": "", "productIds": "AKT_ALL_PRODUCTS;PROD-06;PROD-04;QA_a00U000000PunQ7IA;PROD-01;a00g000000BoMJfAAN;Decloremaxo;QA_DSM00002pro;QA_DSM00001pro;QA_a00U000000PunPvIA;QA_a00U000000XL37cIA;a00g000000BoMKEAA3;Mentisan;PROD-05;Omparasol;PROD-03;QA_a00U000000PunPcIA;PROD-02;a00g000000BoMKTAA3", "accountPriorityInfluence": "0", "pacingAcceleration": "-1", "rules": [ { "type": "eventFactor", "comparisonValue1": "0", "comparisonValue2": "10", "operator1": ">=", "operator2": "<=", "condition": "AND", "negated": "false", "fixedDate": null, "productId": null, "strict": false, "includeNullValue": "false", "nonRule": false, "ruleUid": "x041f6183a6f36add9ca896ea893a36b4c31a", "eventTypeId": "VISIT_DETAIL-MISSED", "linkedRules": [] }, { "type": "fixedDateFactor", "comparisonValue1": "0", "comparisonValue2": "10", "operator1": ">=", "operator2": "<=", "condition": "AND", "negated": "false", "fixedDate": "2020-09-24", "productId": null, "strict": false, "includeNullValue": "false", "nonRule": false, "ruleUid": "x7a0f1137a1c9aa5eb8a2a61a63487a05954a", "fixedDateTypeId": "calendarDate", "linkedRules": [] } ], "reasonTemplates": [ { "tokenizedText": null, "crmFieldName": "", "destination": "Suggestion" }, { "tokenizedText": null, "crmFieldName": "", "destination": "Insight" }, { "tokenizedText": null, "crmFieldName": "", "destination": "EnhancedInsight" } ] }, { "factorTypeId": "notificationFactor", "order": 6, "id": "a7217488-1012-a12f-57ac-201d4783aa85", "masterFactorId": null, "excludedMasterFactorProductIds": "", "remEnabled": "false", "requirements": "", "isAnyRuleModified": false, "disabled": false, "suggestionTitleMVEL": null, "insightTitleMVEL": null, "enhancedInsightTitleMVEL": null, "segmentFactorIds": [], "segmentsGroupingCondition": "AND", "evaluationFrequency": "DAILY", "name": "New Insights Factor", "description": "", "productIds": "AKT_ALL_PRODUCTS;PROD-06;PROD-04;QA_a00U000000PunQ7IA;PROD-01;a00g000000BoMJfAAN;Decloremaxo;QA_DSM00002pro;QA_DSM00001pro;QA_a00U000000PunPvIA;QA_a00U000000XL37cIA;a00g000000BoMKEAA3;Mentisan;PROD-05;Omparasol;PROD-03;QA_a00U000000PunPcIA;PROD-02;a00g000000BoMKTAA3", "rules": [ { "type": "fixedDateFactor", "comparisonValue1": "0", "comparisonValue2": "10", "operator1": ">=", "operator2": "<=", "condition": "AND", "negated": "false", "fixedDate": null, "productId": null, "strict": false, "includeNullValue": "false", "nonRule": false, "ruleUid": "x2cd90832ae766af58aabb7ca9a3d2b527e6e", "fixedDateTypeId": "firstOfCurrentMonth", "linkedRules": [] }, { "type": "eventFactor", "comparisonValue1": "15", "comparisonValue2": "0", "operator1": ">=", "operator2": "<=", "condition": "AND", "negated": "false", "fixedDate": null, "productId": null, "strict": false, "includeNullValue": "false", "nonRule": false, "ruleUid": "x2159b516a3f12a63bea39b0a1d548ae06b66", "eventTypeId": "VISIT_DETAIL-PLANNED", "linkedRules": [] } ], "tags": [ { "tagId": 6, "tagName": "Email consen", "tagDescription": null, "tagRank": 1, "tagType": "USECASE" } ], "reasonTemplates": [ { "tokenizedText": null, "crmFieldName": "", "destination": "Suggestion" }, { "tokenizedText": null, "crmFieldName": "", "destination": "Insight" }, { "tokenizedText": null, "crmFieldName": "", "destination": "EnhancedInsight" } ] }, { "factorTypeId": "suppressionFactor", "order": 7, "id": "9681059a-7842-5c5a-839a-8d056869c01d", "masterFactorId": null, "excludedMasterFactorProductIds": "", "remEnabled": "false", "requirements": "", "isAnyRuleModified": false, "disabled": false, "suggestionTitleMVEL": null, "insightTitleMVEL": null, "enhancedInsightTitleMVEL": null, "segmentFactorIds": [], "segmentsGroupingCondition": "AND", "evaluationFrequency": "DAILY", "name": "New Suppress Factor", "description": "", "actorTypeId": "MSL", "optionalMessages": "AKT_ALL_PRODUCTS:;PROD-06:;PROD-04:;QA_a00U000000PunQ7IA:;PROD-01:;a00g000000BoMJfAAN:;Decloremaxo:;QA_DSM00002pro:;QA_DSM00001pro:;QA_a00U000000PunPvIA:;QA_a00U000000XL37cIA:;a00g000000BoMKEAA3:;Mentisan:;PROD-05:;Omparasol:;PROD-03:;QA_a00U000000PunPcIA:;PROD-02:;a00g000000BoMKTAA3:", "productIds": "AKT_ALL_PRODUCTS;PROD-06;PROD-04;QA_a00U000000PunQ7IA;PROD-01;a00g000000BoMJfAAN;Decloremaxo;QA_DSM00002pro;QA_DSM00001pro;QA_a00U000000PunPvIA;QA_a00U000000XL37cIA;a00g000000BoMKEAA3;Mentisan;PROD-05;Omparasol;PROD-03;QA_a00U000000PunPcIA;PROD-02;a00g000000BoMKTAA3", "channelId": "VISIT_CHANNEL", "suppressedDestination": "Insight", "rules": [ { "type": "eventFactor", "comparisonValue1": "15", "comparisonValue2": "0", "operator1": ">=", "operator2": "<=", "condition": "AND", "negated": "false", "fixedDate": null, "productId": "QA_a00U000000PunPcIA", "strict": true, "includeNullValue": "false", "nonRule": false, "ruleUid": "x788f8a69a3395a2389af7c5a4141522e7b77", "eventTypeId": "VISIT_DETAIL-MISSED", "linkedRules": [] }, { "type": "metricFactor", "comparisonValue1": "A|B|C", "comparisonValue2": null, "operator1": "all of", "operator2": "", "condition": "", "negated": "false", "fixedDate": null, "productId": "QA_a00U000000PunPcIA", "strict": true, "includeNullValue": "false", "nonRule": false, "ruleUid": "x27757fa3a8b2ca2135a179da15b65464b9fb", "metricTypeId": "hcpSegment_std_akt", "linkedRules": [] }, { "type": "labelValueMetricFactor", "comparisonValue1": "0", "comparisonValue2": null, "operator1": ">", "operator2": "", "condition": "", "negated": "false", "fixedDate": null, "productId": "QA_a00U000000PunPvIA", "strict": true, "includeNullValue": "false", "nonRule": false, "ruleUid": "xaf7109d7ae861aff4faf78ea1696a5e6c298", "labelValueMetricTypeId": "MONTHLY_SALES", "linkedRules": [ { "type": "labelValueMetricFactor", "comparisonValue1": "0", "comparisonValue2": null, "operator1": ">", "operator2": "", "condition": "", "negated": "false", "fixedDate": null, "productId": null, "strict": false, "includeNullValue": "false", "nonRule": false, "labelValueMetricTypeId": "value" } ] } ], "tags": [ { "tagId": 89, "tagName": "Handover from field to MA", "tagDescription": null, "tagRank": 1, "tagType": "USECASE" } ], "reasonTemplates": [ { "tokenizedText": "", "crmFieldName": "", "destination": "Suggestion" }, { "tokenizedText": "", "crmFieldName": "", "destination": "Insight" }, { "tokenizedText": "", "crmFieldName": "", "destination": "EnhancedInsight" } ] }, { "factorTypeId": "triggerFactor", "order": 8, "id": "58afd459-1d9d-a15e-b471-ff7b8be219cc", "masterFactorId": null, "excludedMasterFactorProductIds": "", "remEnabled": "false", "requirements": "", "isAnyRuleModified": false, "disabled": false, "suggestionTitleMVEL": null, "insightTitleMVEL": null, "enhancedInsightTitleMVEL": null, "segmentFactorIds": [], "segmentsGroupingCondition": "AND", "evaluationFrequency": "DAILY", "name": "New Trigger Factor", "description": "", "actorTypeId": "FieldRep", "optionalMessages": "AKT_ALL_PRODUCTS:;PROD-06:;PROD-04:;QA_a00U000000PunQ7IA:;PROD-01:;a00g000000BoMJfAAN:;Decloremaxo:;QA_DSM00002pro:;QA_DSM00001pro:;QA_a00U000000PunPvIA:;QA_a00U000000XL37cIA:;a00g000000BoMKEAA3:;Mentisan:;PROD-05:;Omparasol:;PROD-03:;QA_a00U000000PunPcIA:;PROD-02:;a00g000000BoMKTAA3:", "actionTypeId": "VISIT_DETAIL", "productIds": "AKT_ALL_PRODUCTS;PROD-06;PROD-04;QA_a00U000000PunQ7IA;PROD-01;a00g000000BoMJfAAN;Decloremaxo;QA_DSM00002pro;QA_DSM00001pro;QA_a00U000000PunPvIA;QA_a00U000000XL37cIA;a00g000000BoMKEAA3;Mentisan;PROD-05;Omparasol;PROD-03;QA_a00U000000PunPcIA;PROD-02;a00g000000BoMKTAA3", "channelId": "VISIT_CHANNEL", "optionalMessageSet": "AKT_ALL_PRODUCTS:;PROD-06:;PROD-04:;QA_a00U000000PunQ7IA:;PROD-01:;a00g000000BoMJfAAN:;Decloremaxo:;QA_DSM00002pro:;QA_DSM00001pro:;QA_a00U000000PunPvIA:;QA_a00U000000XL37cIA:;a00g000000BoMKEAA3:;Mentisan:;PROD-05:;Omparasol:;PROD-03:;QA_a00U000000PunPcIA:;PROD-02:;a00g000000BoMKTAA3:", "rules": [ { "type": "eventFactor", "comparisonValue1": "0", "comparisonValue2": "0", "operator1": ">=", "operator2": "<=", "condition": "AND", "negated": "false", "fixedDate": null, "productId": null, "strict": false, "includeNullValue": "false", "nonRule": false, "ruleUid": "x81c65090a331cabb03a81f9a57f163a91e49", "eventTypeId": "VISIT_DETAIL-PLANNED", "linkedRules": [] } ], "tags": [ { "tagId": 6, "tagName": "Email consen", "tagDescription": null, "tagRank": 1, "tagType": "USECASE" } ], "reasonTemplates": [ { "tokenizedText": null, "crmFieldName": "", "destination": "Suggestion" }, { "tokenizedText": null, "crmFieldName": "", "destination": "Insight" }, { "tokenizedText": null, "crmFieldName": "", "destination": "EnhancedInsight" } ] }, { "factorTypeId": "triggerFactor", "order": 8, "id": "58afd459-1234-5678-90ab-ff7b8be219cc", "masterFactorId": null, "excludedMasterFactorProductIds": "", "remEnabled": "false", "requirements": "", "isAnyRuleModified": false, "disabled": false, "suggestionTitleMVEL": null, "insightTitleMVEL": null, "enhancedInsightTitleMVEL": null, "segmentFactorIds": [], "segmentsGroupingCondition": "AND", "evaluationFrequency": "DAILY", "name": "New Trigger Factor", "description": "", "actorTypeId": "FieldRep", "actionTypeId": "VISIT_DETAIL", "productIds": "AKT_ALL_PRODUCTS;PROD-06;PROD-04;QA_a00U000000PunQ7IA;PROD-01;a00g000000BoMJfAAN;Decloremaxo;QA_DSM00002pro;QA_DSM00001pro;QA_a00U000000PunPvIA;QA_a00U000000XL37cIA;a00g000000BoMKEAA3;Mentisan;PROD-05;Omparasol;PROD-03;QA_a00U000000PunPcIA;PROD-02;a00g000000BoMKTAA3", "channelId": "VISIT_CHANNEL", "optionalMessages": "AKT_ALL_PRODUCTS:;PROD-06:;PROD-04:;QA_a00U000000PunQ7IA:;PROD-01:;a00g000000BoMJfAAN:;Decloremaxo:;QA_DSM00002pro:;QA_DSM00001pro:;QA_a00U000000PunPvIA:;QA_a00U000000XL37cIA:;a00g000000BoMKEAA3:;Mentisan:;PROD-05:;Omparasol:;PROD-03:;QA_a00U000000PunPcIA:;PROD-02:;a00g000000BoMKTAA3:", "optionalMessageSet": "AKT_ALL_PRODUCTS:;PROD-06:;PROD-04:;QA_a00U000000PunQ7IA:;PROD-01:;a00g000000BoMJfAAN:;Decloremaxo:;QA_DSM00002pro:;QA_DSM00001pro:;QA_a00U000000PunPvIA:;QA_a00U000000XL37cIA:;a00g000000BoMKEAA3:;Mentisan:;PROD-05:;Omparasol:;PROD-03:;QA_a00U000000PunPcIA:;PROD-02:;a00g000000BoMKTAA3:", "rules": [ { "type": "eventFactor", "comparisonValue1": "0", "comparisonValue2": "0", "operator1": ">=", "operator2": "<=", "condition": "AND", "negated": "false", "fixedDate": null, "productId": null, "strict": false, "includeNullValue": "false", "nonRule": false, "ruleUid": "x81c65090a331cabb03a81f9a57f163a91e49", "eventTypeId": "VISIT_DETAIL-PLANNED", "linkedRules": [] } ], "tags": [ { "tagId": 6, "tagName": "Email consen", "tagDescription": null, "tagRank": 1, "tagType": "USECASE" } ], "reasonTemplates": [ { "tokenizedText": null, "crmFieldName": "", "destination": "Suggestion" }, { "tokenizedText": null, "crmFieldName": "", "destination": "Insight" }, { "tokenizedText": null, "crmFieldName": "", "destination": "EnhancedInsight" } ] } ] }, "directory": null, "configLock": { "lockUID": "", "entityId": "210-2", "lockOwner": "demo", "lockOwnerName": "demo", "lockExpiration": "2020-09-28T18:01:24Z", "disableConfigLocking": "false" } }`); var myCopy = null; var cloneDeep = function(obj) { if (!obj || typeof obj !== 'object') { return obj; } else if (_.isString(obj)) { return String.prototype.slice.call(obj); } else if (_.isDate(obj)) { return new Date(obj.getTime()); } else if (_.isFunction(obj.clone)) { return obj.clone(); } else if (_.isArray(obj)) { return _.map(obj, (t) => { return cloneDeep(t); }); } else { return _.mapValues(obj, (val) => { return cloneDeep(val); }); } }; var clone = (function() { 'use strict'; function _instanceof(obj, type) { return type != null && obj instanceof type; } var nativeMap; try { nativeMap = Map; } catch(_) { // maybe a reference error because no `Map`. Give it a dummy value that no // value will ever be an instanceof. nativeMap = function() {}; } var nativeSet; try { nativeSet = Set; } catch(_) { nativeSet = function() {}; } var nativePromise; try { nativePromise = Promise; } catch(_) { nativePromise = function() {}; } /** * Clones (copies) an Object using deep copying. * * This function supports circular references by default, but if you are certain * there are no circular references in your object, you can save some CPU time * by calling clone(obj, false). * * Caution: if `circular` is false and `parent` contains circular references, * your program may enter an infinite loop and crash. * * @param `parent` - the object to be cloned * @param `circular` - set to true if the object to be cloned may contain * circular references. (optional - true by default) * @param `depth` - set to a number if the object is only to be cloned to * a particular depth. (optional - defaults to Infinity) * @param `prototype` - sets the prototype to be used when cloning an object. * (optional - defaults to parent prototype). * @param `includeNonEnumerable` - set to true if the non-enumerable properties * should be cloned as well. Non-enumerable properties on the prototype * chain will be ignored. (optional - false by default) */ function clone(parent, circular, depth, prototype, includeNonEnumerable) { if (typeof circular === 'object') { depth = circular.depth; prototype = circular.prototype; includeNonEnumerable = circular.includeNonEnumerable; circular = circular.circular; } // maintain two arrays for circular references, where corresponding parents // and children have the same index var allParents = []; var allChildren = []; var useBuffer = typeof Buffer != 'undefined'; if (typeof circular == 'undefined') circular = true; if (typeof depth == 'undefined') depth = Infinity; // recurse this function so we don't reset allParents and allChildren function _clone(parent, depth) { // cloning null always returns null if (parent === null) return null; if (depth === 0) return parent; var child; var proto; if (typeof parent != 'object') { return parent; } if (_instanceof(parent, nativeMap)) { child = new nativeMap(); } else if (_instanceof(parent, nativeSet)) { child = new nativeSet(); } else if (_instanceof(parent, nativePromise)) { child = new nativePromise(function (resolve, reject) { parent.then(function(value) { resolve(_clone(value, depth - 1)); }, function(err) { reject(_clone(err, depth - 1)); }); }); } else if (clone.__isArray(parent)) { child = []; } else if (clone.__isRegExp(parent)) { child = new RegExp(parent.source, __getRegExpFlags(parent)); if (parent.lastIndex) child.lastIndex = parent.lastIndex; } else if (clone.__isDate(parent)) { child = new Date(parent.getTime()); } else if (useBuffer && Buffer.isBuffer(parent)) { if (Buffer.from) { // Node.js >= 5.10.0 child = Buffer.from(parent); } else { // Older Node.js versions child = new Buffer(parent.length); parent.copy(child); } return child; } else if (_instanceof(parent, Error)) { child = Object.create(parent); } else { if (typeof prototype == 'undefined') { proto = Object.getPrototypeOf(parent); child = Object.create(proto); } else { child = Object.create(prototype); proto = prototype; } } if (circular) { var index = allParents.indexOf(parent); if (index != -1) { return allChildren[index]; } allParents.push(parent); allChildren.push(child); } if (_instanceof(parent, nativeMap)) { parent.forEach(function(value, key) { var keyChild = _clone(key, depth - 1); var valueChild = _clone(value, depth - 1); child.set(keyChild, valueChild); }); } if (_instanceof(parent, nativeSet)) { parent.forEach(function(value) { var entryChild = _clone(value, depth - 1); child.add(entryChild); }); } for (var i in parent) { var attrs = Object.getOwnPropertyDescriptor(parent, i); if (attrs) { child[i] = _clone(parent[i], depth - 1); } try { var objProperty = Object.getOwnPropertyDescriptor(parent, i); if (objProperty.set === 'undefined') { // no setter defined. Skip cloning this property continue; } child[i] = _clone(parent[i], depth - 1); } catch(e){ if (e instanceof TypeError) { // when in strict mode, TypeError will be thrown if child[i] property only has a getter // we can't do anything about this, other than inform the user that this property cannot be set. continue } else if (e instanceof ReferenceError) { //this may happen in non strict mode continue } } } if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(parent); for (var i = 0; i < symbols.length; i++) { // Don't need to worry about cloning a symbol because it is a primitive, // like a number or string. var symbol = symbols[i]; var descriptor = Object.getOwnPropertyDescriptor(parent, symbol); if (descriptor && !descriptor.enumerable && !includeNonEnumerable) { continue; } child[symbol] = _clone(parent[symbol], depth - 1); Object.defineProperty(child, symbol, descriptor); } } if (includeNonEnumerable) { var allPropertyNames = Object.getOwnPropertyNames(parent); for (var i = 0; i < allPropertyNames.length; i++) { var propertyName = allPropertyNames[i]; var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName); if (descriptor && descriptor.enumerable) { continue; } child[propertyName] = _clone(parent[propertyName], depth - 1); Object.defineProperty(child, propertyName, descriptor); } } return child; } return _clone(parent, depth); } /** * Simple flat clone using prototype, accepts only objects, usefull for property * override on FLAT configuration object (no nested props). * * USE WITH CAUTION! This may not behave as you wish if you do not know how this * works. */ clone.clonePrototype = function clonePrototype(parent) { if (parent === null) return null; var c = function () {}; c.prototype = parent; return new c(); }; // private utility functions function __objToStr(o) { return Object.prototype.toString.call(o); } clone.__objToStr = __objToStr; function __isDate(o) { return typeof o === 'object' && __objToStr(o) === '[object Date]'; } clone.__isDate = __isDate; function __isArray(o) { return typeof o === 'object' && __objToStr(o) === '[object Array]'; } clone.__isArray = __isArray; function __isRegExp(o) { return typeof o === 'object' && __objToStr(o) === '[object RegExp]'; } clone.__isRegExp = __isRegExp; function __getRegExpFlags(re) { var flags = ''; if (re.global) flags += 'g'; if (re.ignoreCase) flags += 'i'; if (re.multiline) flags += 'm'; return flags; } clone.__getRegExpFlags = __getRegExpFlags; return clone; })();
Tests:
Lodash cloneDeep
myCopy = _.cloneDeep(MyObject);
Native structuredClone
myCopy = structuredClone(MyObject);
clone();
myCopy = clone(MyObject, false);
_cloneDeep custom underscore/lodash
myCopy = cloneDeep(MyObject);