Deep understanding of JavaScript deep copy performance
This article mainly shares with you the analysis of JavaScript deep copy performance. How to copy an object in JavaScript? This is a very simple question, but the answer is not simple.
If you don't know what it means, take a look at the following example:
function mutate(obj) { obj.a = true; } const obj = {a: false}; mutate(obj) console.log(obj.a); // 输出 true
Function mutate
changes its parameters. In the value-passing scenario, the formal parameter of the function is just a copy of the actual parameter - a copy - and the actual parameter is not changed when the function call is completed. But in JavaScript's pass-by-reference scenario, the formal parameters and actual parameters of the function point to the same object. When the formal parameters are changed inside the parameters, the actual parameters outside the function are also changed.
So in some cases, you need to retain the original object. In this case, you need to pass a copy of the original object into the function to prevent the function from changing the original object.
Shallow copy: Object.assign()
A simple way to obtain a copy of an object is to use Object.assign(target, sources...)
. It accepts any number of source objects, enumerates all their properties and assigns them to target
. If we use a new empty object target
, then we can copy the object.
const obj = /* ... */; const copy = Object.assign({}, obj);
However this is just a shallow copy. If our objects contain other objects as their properties, they will maintain shared references, which is not what we want:
function mutateDeepObject(obj) { obj.a.thing = true; } const obj = {a: {thing: false}}; const copy = Object.assign({}, obj); mutateDeepObject(copy) console.log(obj.a.thing); // prints true
Object.assign
Method will only copy the source object Own and enumerable properties to the target object. This method uses the[[Get]]
of the source object and the[[Set]]
of the target object, so it calls the relevantgetter
andsetter
. Therefore, it assigns properties rather than just copying or defining new properties. If the merge source containsgetter
, this may make it unsuitable for merging new properties into the prototype. In order to copy a property definition (including its enumerability) to the prototype,Object.getOwnPropertyDescriptor()
andObject.defineProperty()
should be used.
So what to do now? There are several ways to create a deep copy of an object.
Note: Maybe someone mentioned the object destructuring operation, which is also a shallow copy.
JSON.parse
One of the oldest ways to create a copy of an object is to convert that object to its JSON
string representation, Then parse it back into an object. This feels a bit oppressive, but it works:
const obj = /* ... */; const copy = JSON.parse(JSON.stringify(obj));
The disadvantage here is that you create a temporary, potentially large string just to put it back into the parser. Another disadvantage is that this method cannot handle cyclic objects. And looping objects happens often. For example, when you build a tree-like data structure, a node refers to its parent, which in turn refers to its children.
const x = {}; const y = {x}; x.y = y; // Cycle: x.y.x.y.x.y.x.y.x... const copy = JSON.parse(JSON.stringify(x)); // throws!
In addition, such as Map
, Set
, RegExp
, Date
, ArrayBuffer
and Other built-in types are lost when serialized.
Structured Clone Structured Cloning Algorithm
Structured cloning is an existing algorithm for transferring values from one place to another. For example, it is used whenever you call postMessage to send a message to another window or WebWorker. The nice thing about structured cloning is that it handles cyclic objects and supports a large number of built-in types. The problem is, at the time of writing this article, the algorithm is not available directly, only as part of other APIs. I guess we should know what's included, shouldn't we. . .
MessageChannel
As I said, the structured cloning algorithm works as long as you call postMessage
. We can create a MessageChannel
and send messages. On the receiving end, the message contains a structured clone of our original data object.
function structuralClone(obj) { return new Promise(resolve => { const {port1, port2} = new MessageChannel(); port2.onmessage = ev => resolve(ev.data); port1.postMessage(obj); }); } const obj = /* ... */; const clone = await structuralClone(obj);
The disadvantage of this method is that it is asynchronous. Although this is not a big deal, sometimes you need to use a synchronous method to deep copy an object.
History API
If you have ever written a SPA using history.pushState(), you know that you can provide a state object to save the URL. It turns out that this state object uses structured cloning - and it's synchronous. We must be careful not to mess up the state objects used by the program logic, so we need to restore the original state after completing the cloning. To prevent any surprises, use history.replaceState() instead of history.pushState().
function structuralClone(obj) { const oldState = history.state; history.replaceState(obj, document.title); const copy = history.state; history.replaceState(oldState, document.title); return copy; } const obj = /* ... */; const clone = structuralClone(obj);
However, using the browser's engine just to copy an object feels a bit excessive. Additionally, Safari browser limits the number of replaceState calls to 100 times in 30 seconds.
Notification API
After a tweet, Jeremy Banks showed me a third way to leverage structured cloning: the Notification API.
function structuralClone(obj) { return new Notification('', {data: obj, silent: true}).data; } const obj = /* ... */; const clone = structuralClone(obj);
Short and concise. I like it!
However, it requires the permission mechanism inside the browser, so I suspect it is very slow. For some reason, Safari always returns undefined
.
Performance extravaganza
I want to measure which method is the most performant. In my first (naive) attempt, I took a small JSON object and cloned the object a thousand times in different ways. Fortunately, Mathias Bynens told me that V8 has a cache when you add properties to an object. So I'm benchmarking the cache. To make sure I never hit the cache, I wrote a function that generates an object of a given depth and width with a random key name and reran the test.
chart!
Here are the performance of different technologies in Chrome, Firefox and Edge. The lower the better.
- If you are not looping over objects and do not need to preserve built-in types, you can use the cross-browser
JSON.parse(JSON.stringify())
to get the most Fast cloning performance, which really surprised me.
- If you want a properly structured clone,
MessageChannel
is your only reliable cross-browser choice.
structuredClone() function? I certainly think so, the latest HTML specification is discussing this Synchronous clone = global.structuredClone(value, transfer = []) API · Issue #793 · whatwg/html.
JQuery’s $.extend shallow copy and deep copy example analysis
Achieve deep copy in jquery Copy and shallow copy
What are shallow and deep copies in Js
The above is the detailed content of Deep understanding of JavaScript deep copy performance. For more information, please follow other related articles on the PHP Chinese website!

The differences in performance and efficiency between Python and JavaScript are mainly reflected in: 1) As an interpreted language, Python runs slowly but has high development efficiency and is suitable for rapid prototype development; 2) JavaScript is limited to single thread in the browser, but multi-threading and asynchronous I/O can be used to improve performance in Node.js, and both have advantages in actual projects.

JavaScript originated in 1995 and was created by Brandon Ike, and realized the language into C. 1.C language provides high performance and system-level programming capabilities for JavaScript. 2. JavaScript's memory management and performance optimization rely on C language. 3. The cross-platform feature of C language helps JavaScript run efficiently on different operating systems.

JavaScript runs in browsers and Node.js environments and relies on the JavaScript engine to parse and execute code. 1) Generate abstract syntax tree (AST) in the parsing stage; 2) convert AST into bytecode or machine code in the compilation stage; 3) execute the compiled code in the execution stage.

The future trends of Python and JavaScript include: 1. Python will consolidate its position in the fields of scientific computing and AI, 2. JavaScript will promote the development of web technology, 3. Cross-platform development will become a hot topic, and 4. Performance optimization will be the focus. Both will continue to expand application scenarios in their respective fields and make more breakthroughs in performance.

Both Python and JavaScript's choices in development environments are important. 1) Python's development environment includes PyCharm, JupyterNotebook and Anaconda, which are suitable for data science and rapid prototyping. 2) The development environment of JavaScript includes Node.js, VSCode and Webpack, which are suitable for front-end and back-end development. Choosing the right tools according to project needs can improve development efficiency and project success rate.

Yes, the engine core of JavaScript is written in C. 1) The C language provides efficient performance and underlying control, which is suitable for the development of JavaScript engine. 2) Taking the V8 engine as an example, its core is written in C, combining the efficiency and object-oriented characteristics of C. 3) The working principle of the JavaScript engine includes parsing, compiling and execution, and the C language plays a key role in these processes.

JavaScript is at the heart of modern websites because it enhances the interactivity and dynamicity of web pages. 1) It allows to change content without refreshing the page, 2) manipulate web pages through DOMAPI, 3) support complex interactive effects such as animation and drag-and-drop, 4) optimize performance and best practices to improve user experience.

C and JavaScript achieve interoperability through WebAssembly. 1) C code is compiled into WebAssembly module and introduced into JavaScript environment to enhance computing power. 2) In game development, C handles physics engines and graphics rendering, and JavaScript is responsible for game logic and user interface.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

VSCode Windows 64-bit Download
A free and powerful IDE editor launched by Microsoft

Dreamweaver CS6
Visual web development tools

Dreamweaver Mac version
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

WebStorm Mac version
Useful JavaScript development tools
