Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

Sorry, you do not have permission to ask a question, You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please type your username.

Please type your E-Mail.

Please choose an appropriate title for the post.

Please choose the appropriate section so your post can be easily searched.

Please choose suitable Keywords Ex: post, video.

Browse

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Navigation

  • Home
  • About Us
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • About Us
  • Contact Us
Home/ Questions/Q 4068

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Latest Questions

Author
  • 61k
Author
Asked: November 26, 20242024-11-26T08:34:10+00:00 2024-11-26T08:34:10+00:00

How to Get a Perfect Deep Copy in JavaScript?

  • 61k

Originally published in my newsletter.

Pre-knowledge

In JavaScript, data types can be categorized into primitive value types and reference value types. The main difference between these types lies in how they are handled and copied in memory.

For primitive value types (such as undefined, null, number, string, boolean, symbol, and bigint), JavaScript uses a pass-by-value method for copying. This means that when a primitive value is assigned to another variable, a copy of the value is actually created. Therefore, if the original variable is modified, the copied variable will not be affected. The following code demonstrates this:

let primitiveValue = 1; const copyPrimitiveValue = primitiveValue; ​ primitiveValue = 2; console.log('primitiveValue: ', primitiveValue); // Outputs 2 console.log('copyPrimitiveValue: ', copyPrimitiveValue); // Outputs 1 
Enter fullscreen mode Exit fullscreen mode

For reference value types, such as objects, arrays, and functions, JavaScript uses a pass-by-reference method. When copying a reference value, what is actually copied is a reference to the object, not a copy of the object itself. This means that if any variable modifies the properties of the object, all variables that reference the object will reflect this change. For example:

const referenceValue = { value: 1 }; const copyReferenceValue = referenceValue; ​ referenceValue.value = 2; console.log('referenceValue: ', referenceValue); // Outputs { value: 2 } console.log('copyReferenceValue: ', copyReferenceValue); // Outputs { value: 2 } 
Enter fullscreen mode Exit fullscreen mode

By this method, JavaScript ensures the independence of primitive values and the connectivity of reference values, making data operations predictable and consistent.

Shallow copy

A shallow copy means that only one layer of the object is copied, and the deep layer of the object directly copies an address. There are many native methods in Javascript that are shallow copies. For example, using Object.assign API or the spread operator.

const target = {}; const source = { a: { b: 1 }, c: 2 }; Object.assign(target, source);  source.a.b = 3; source.c = 4;  console.log(source); // { a: { b: 3 }, c: 4 } console.log(target); // { a: { b: 3 }, c: 2 }  // Same effect as Object.assign const target1 = { ...source }; 
Enter fullscreen mode Exit fullscreen mode

Deep copy

Deep copy means cloning two identical objects but without any connection to each other.

1. JSON.stringify API

const source = { a: { b: 1 } }; const target = JSON.parse(JSON.stringify(source));  source.a.b = 2; console.log(source); // { a: { b: 2 } }; console.log(target); // { a: { b: 1 } }; 
Enter fullscreen mode Exit fullscreen mode

Well, it seems that JSON.stringify can implement deep copying, but it has some defects. For example, it cannot copy functions, undefined, Date, cannot copy non-enumerable properties, cannot copy circularly referenced objects, and so on. You can check out the detailed description on MDN.

2. structuredClone API

I've found that there's already a native API called structuredClone, designed specifically for this purpose. It creates a deep clone of a given value using the structured clone algorithm. This means Function objects cannot be cloned and will throw a DataCloneError exception. It also doesn't clone setters, getters, and similar metadata functionalities.

3. Almost perfect deep copy

const deepClone = (obj, map = new WeakMap()) => {   if (obj instanceof Date) return new Date(obj);   if (obj instanceof RegExp) return new RegExp(obj);    if (map.has(obj)) {     return map.get(obj);   }    const allDesc = Object.getOwnPropertyDescriptors(obj);   const cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc);    map.set(obj, cloneObj);    for (const key of Reflect.ownKeys(obj)) {     const value = obj[key];      cloneObj[key] =       value instanceof Object && typeof value !== 'function'         ? deepClone(value, map)         : value;   }    return cloneObj; }; 
Enter fullscreen mode Exit fullscreen mode

The above code is the final result, let me explain how it came from.

  1. First, we use WeakMap as a hash table to solve the circular reference problem, which can effectively prevent memory leaks. You can check the description of WeakMap on MDN.

  2. For the special types Date and RegExp, a new instance is directly generated and returned.

  3. Use Object.getOwnPropertyDescriptors to get all property descriptions of the current object, and use Object.getPrototypeOfto get the prototype of the current object. Passing these two items as arguments to Object.create API to create a new object with the same prototype and the same properties.

  4. Use Reflect.ownKeys to iterate over all properties of the current object, including non-enumerable properties and Symbol properties, as well as normal properties. In this way, the deep-seated value can be continuously copied into the current new object in the loop and recursion.

  5. In the loop judgment, except that the function is directly assigned, the others are re-copied by recursion.

Next, we can use the test code to verify.

const symbolKey = Symbol('symbolKey');  const originValue = {   num: 0,   str: '',   boolean: true,   unf: void 0,   nul: null,   obj: { name: 'object', id: 1 },   arr: [0, 1, 2],   func() {     console.log('function');   },   date: new Date(0),   reg: new RegExp('/regexp/ig'),   [symbolKey]: 'symbol', };  Object.defineProperty(originValue, 'innumerable', {   // writable is true to ensure that the assignment operator can be used   writable: true,   enumerable: false,   value: 'innumerable', });  // Create circular reference originValue.loop = originValue;  // Deep Copy const clonedValue = deepClone(originValue);  // Change original value originValue.arr.push(3); originValue.obj.name = 'newObject';  // Remove circular reference originValue.loop = ''; originValue[symbolKey] = 'newSymbol';  console.log('originValue: ', originValue); console.log('clonedValue: ', clonedValue); 
Enter fullscreen mode Exit fullscreen mode

Image description

Great, it looks like it's working well.


If you find this helpful, please consider subscribing to my newsletter for more insights on web development. Thank you for reading!

frontendjavascriptprogrammingwebdev
  • 0 0 Answers
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

Sidebar

Ask A Question

Stats

  • Questions 4k
  • Answers 0
  • Best Answers 0
  • Users 2k
  • Popular
  • Answers
  • Author

    ES6 - A beginners guide - Template Literals

    • 0 Answers
  • Author

    Understanding Higher Order Functions in JavaScript.

    • 0 Answers
  • Author

    Build a custom video chat app with Daily and Vue.js

    • 0 Answers

Top Members

Samantha Carter

Samantha Carter

  • 0 Questions
  • 20 Points
Begginer
Ella Lewis

Ella Lewis

  • 0 Questions
  • 20 Points
Begginer
Isaac Anderson

Isaac Anderson

  • 0 Questions
  • 20 Points
Begginer

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help

Footer

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore, ask, and connect. Join our vibrant Q&A community today!

About Us

  • About Us
  • Contact Us
  • All Users

Legal Stuff

  • Terms of Use
  • Privacy Policy
  • Cookie Policy

Help

  • Knowledge Base
  • Support

Follow

© 2022 Querify Question. All Rights Reserved

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.