この記事では主に JavaScript のディープ コピー パフォーマンスの分析について説明します。JavaScript でオブジェクトをコピーする方法。これは非常に単純な質問ですが、答えは簡単ではありません。
その意味がわからない場合は、次の例を見てください:
function mutate(obj) { obj.a = true; } const obj = {a: false}; mutate(obj) console.log(obj.a); // 输出 true
関数 mutate
は引数を変更します。 値渡しのシナリオでは、関数の仮パラメータは実際のパラメータのコピー (コピー) にすぎず、関数呼び出しの完了後に実際のパラメータは変更されません。しかし、JavaScript の参照渡しのシナリオでは、関数の仮パラメータと実パラメータは同じオブジェクトを指します。パラメータ内で仮パラメータが変更されると、関数の外部の実パラメータも変更されます。かわった。 mutate
改变了它的参数。在值传递的场景中,函数的形参只是实参的一个副本——a copy——当函数调用完成后,并不改变实参。但是在 JavaScript 这种引用传递的场景中,函数的形参和实参指向同一个对象,当参数内部改变形参的时候,函数外面的实参也被改变了。
因此在某些情况下,你需要保留原始对象,这时你需要把原始对象的一个拷贝传入到函数中,以防止函数改变原始对象。
浅拷贝:Object.assign()
一个简单的获取对象拷贝的方式是使用 Object.assign(target, sources...)
。它接受任意数量的源对象,枚举它们的所有属性并分配给target
。如果我们使用一个新的空对象target
,那么我们就可以实现对象的复制。
const obj = /* ... */; const copy = Object.assign({}, obj);
然而这只是一个浅副本。如果我们的对象包含其它对象作为自己的属性,它们将保持共享引用,这不是我们想要的:
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
方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]
和目标对象的[[Set]]
,所以它会调用相关getter
和setter
。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter
,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()
和Object.defineProperty()
。
所以现在怎么办?有几种方法可以创建一个对象的深拷贝。
注意:也许有人提到了对象解构运算,这也是浅拷贝。
JSON.parse
创建对象副本的最古老方法之一是:将该对象转换为其 JSON
字符串表示形式,然后将其解析回对象。这感觉有点压抑,但它确实有效:
const obj = /* ... */; const copy = JSON.parse(JSON.stringify(obj));
这里的缺点是你创建一个临时的,可能很大的字符串,只是为了把它重新放回解析器。另一个缺点是这种方法不能处理循环对象。而且循环对象经常发生。例如,当您构建树状数据结构,其中一个节点引用其父级,而父级又引用其子级。
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!
另外,诸如 Map
, Set
, RegExp
, Date
, ArrayBuffer
和其他内置类型在进行序列化时会丢失。
Structured Clone 结构化克隆算法
Structured cloning 是一种现有的算法,用于将值从一个地方转移到另一地方。例如,每当您调用postMessage将消息发送到另一个窗口或 WebWorker 时,都会使用它。关于结构化克隆的好处在于它处理循环对象并 支持大量的内置类型。问题是,在编写本文时,该算法并不能直接使用,只能作为其他 API 的一部分。我想我们应该了解一下包含哪些,不是吗。。。
MessageChannel
正如我所说的,只要你调用postMessage
结构化克隆算法就可以使用。我们可以创建一个 MessageChannel
并发送消息。在接收端,消息包含我们原始数据对象的结构化克隆。
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);
这种方法的缺点是它是异步的。虽然这并无大碍,但是有时候你需要使用同步的方式来深度拷贝一个对象。
History API
如果你曾经使用history.pushState()写过 SPA,你就知道你可以提供一个状态对象来保存 URL。事实证明,这个状态对象使用结构化克隆 - 而且是同步的。我们必须小心使用,不要把程序逻辑使用的状态对象搞乱了,所以我们需要在完成克隆之后恢复原始状态。为了防止发生任何意外,请使用history.replaceState()而不是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);
然而,仅仅为了复制一个对象,而使用浏览器的引擎,感觉有点过分。另外,Safari 浏览器对replaceState调用的限制数量为 30 秒内 100 次。
Notification API
在发了一条推文之后,Jeremy Banks 向我展示了第三种方法来利用结构化克隆:Notification API。
function structuralClone(obj) { return new Notification('', {data: obj, silent: true}).data; } const obj = /* ... */; const clone = structuralClone(obj);
短小,简洁。我喜欢它!
但是,它需要浏览器内部的权限机制,所以我怀疑它是很慢的。由于某种原因,Safari 总是返回undefined
浅いコピー: Object.assign()
🎜 オブジェクトのコピーを取得する簡単な方法は、Object.assign(target,sources... を使用することです) )コード>。任意の数のソース オブジェクトを受け入れ、そのすべてのプロパティを列挙し、それらを <code>target
に割り当てます。新しい空のオブジェクト target
を使用すると、そのオブジェクトをコピーできます。 🎜rrreee🎜 ただし、 これは浅いコピーにすぎません。オブジェクトに他のオブジェクトがプロパティとして含まれている場合、それらは共有参照を保持しますが、これは私たちが望んでいることではありません: 🎜rrreee🎜それではどうなるでしょうか?オブジェクトのディープ コピーを作成するには、いくつかの方法があります。 🎜🎜注: おそらく誰かがオブジェクトの構造化操作について言及しましたが、これも浅いコピーです。 🎜Object.assign
メソッドはソース オブジェクト自体をコピーするだけであり、列挙可能ですターゲット オブジェクトにプロパティを追加します。このメソッドは、ソース オブジェクトの[[Get]]
とターゲット オブジェクトの[[Set]]
を使用するため、関連するgetter
と セッターコード>。したがって、単に新しいプロパティをコピーまたは定義するのではなく、プロパティを割り当てます。マージ ソースにgetter
が含まれている場合、新しいプロパティをプロトタイプにマージするのに適さない可能性があります。プロパティ定義 (その列挙可能性を含む) をプロトタイプにコピーするには、Object.getOwnPropertyDescriptor()
とObject.defineProperty()
を使用します。
JSON.parse
🎜 オブジェクトのコピーを作成する最も古い方法の 1 つは、オブジェクトを JSON
文字列表現に変換してから、それを解析してオブジェクトに戻します。これは少し圧迫的に感じますが、うまくいきます: 🎜rrreee🎜 ここでの欠点は、パーサーに戻すためだけに一時的な、潜在的に大きな文字列を作成することです。もう 1 つの欠点は、このメソッドでは循環オブジェクトを処理できないことです。また、オブジェクトのループが頻繁に発生します。たとえば、ツリー状のデータ構造を構築する場合、ノードはその親を参照し、さらにその親がその子を参照します。 🎜rrreee🎜さらに、Map
、Set
、RegExp
、Date
、ArrayBuffer などcode> およびその他の組み込み型はシリアル化時に失われます。 🎜<h2 id="構造化クローン-構造化クローン作成アルゴリズム">構造化クローン 構造化クローン作成アルゴリズム</h2>🎜 構造化クローンは、値をある場所から別の場所に転送するために使用される既存のアルゴリズムです。たとえば、別のウィンドウまたは WebWorker にメッセージを送信するために postMessage を呼び出すたびに使用されます。構造化クローン作成の優れた点は、循環オブジェクトを処理し、多数の組み込み型をサポートしていることです。問題は、この記事の執筆時点では、このアルゴリズムは直接利用できず、他の API の一部としてのみ利用できることです。何が含まれているかを知る必要があると思います。 。 。 🎜<h3 id="MessageChannel">MessageChannel</h3>🎜 先ほども述べたように、構造化クローン作成アルゴリズムは、<code>postMessage
を呼び出している限り機能します。 MessageChannel
を作成してメッセージを送信できます。受信側では、メッセージには元のデータ オブジェクトの構造化されたクローンが含まれています。 🎜rrreee🎜 このアプローチの欠点は、非同期であることです。これは問題ありませんが、オブジェクトを同期的にディープ コピーする必要がある場合があります。 🎜History API
🎜 history.pushState() を使用して SPA を作成したことがある場合は、URL を保存するための状態オブジェクトを提供できることをご存知でしょう。強い>。この状態オブジェクトは構造化されたクローン作成を使用しており、同期していることがわかります。プログラム ロジックで使用される状態オブジェクトを台無しにしないように注意する必要があるため、クローン作成の完了後に元の状態に復元する必要があります。予期せぬ事態を避けるために、history.pushState() の代わりに history.replaceState() を使用してください。 🎜rrreee🎜 ただし、オブジェクトをコピーするためだけにブラウザのエンジンを使用するのは、少しやりすぎのように感じます。さらに、Safari では、replaceState 呼び出しの数が 30 秒間に 100 回に制限されています。 🎜通知 API
🎜 ツイートの後、Jeremy Banks は構造化クローンを活用する 3 番目の方法である通知 API を教えてくれました。 🎜rrreee🎜短くて簡潔です。私はそれが好きです! 🎜🎜ただし、ブラウザ内の許可メカニズムが必要なので、非常に遅いのではないかと思います。何らかの理由で、Safari は常にunknown
を返します。 🎜パフォーマンスの祭典
どの方法が最もパフォーマンスが高いかを測定したいと思います。最初の (単純な) 試みでは、小さな JSON オブジェクトを取得し、そのオブジェクトをさまざまな方法で 1,000 回複製しました。幸いなことに、Mathias Bynens は、オブジェクトにプロパティを追加するときに V8 にはキャッシュがあると教えてくれました。そこでキャッシュのベンチマークを行っています。キャッシュにヒットしないようにするために、ランダムなキー名で指定された深さと幅のオブジェクトを生成する関数を作成し、テストを再実行しました。
チャート!
ここでは、Chrome、Firefox、Edge のさまざまなテクノロジーのパフォーマンスを示します。低いほど良いです。
結論
それで、ここから何が得られたでしょうか?
ループ オブジェクトがなく、組み込み型を保持する必要がない場合は、クロスブラウザーの
JSON.parse(JSON.stringify())
を使用できます。クローン作成のパフォーマンスが最も速く、非常に驚きました。JSON.parse(JSON.stringify())
获得最快的克隆性能,这让我感到非常惊讶。如果你想要一个适当的结构化克隆,
MessageChannel
是你唯一可靠的跨浏览器的选择。
如果浏览器平台直接提供一个 structuredClone()
適切に構造化されたクローンが必要な場合は、MessageChannel
が唯一の信頼できるクロスブラウザー オプションです。
structurdClone()
関数を直接提供した方がよいでしょうか?確かにそう思います。最新の HTML 仕様では、この Synchronous clone = global.structurdClone(value, transfer = []) API · Issue #793 · whatwg/html について議論しています。
jQuery の $.extend 浅いコピーと深いコピーの例の分析
🎜🎜 Js の浅いコピーと深いコピーとは何ですか🎜🎜以上がJavaScript ディープコピーのパフォーマンスについての深い理解の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

JavaScriptフレームワークのパワーは、開発を簡素化し、ユーザーエクスペリエンスとアプリケーションのパフォーマンスを向上させることにあります。フレームワークを選択するときは、次のことを検討してください。1。プロジェクトのサイズと複雑さ、2。チームエクスペリエンス、3。エコシステムとコミュニティサポート。

はじめに私はあなたがそれを奇妙に思うかもしれないことを知っています、JavaScript、C、およびブラウザは正確に何をしなければなりませんか?彼らは無関係であるように見えますが、実際、彼らは現代のウェブ開発において非常に重要な役割を果たしています。今日は、これら3つの間の密接なつながりについて説明します。この記事を通して、JavaScriptがブラウザでどのように実行されるか、ブラウザエンジンでのCの役割、およびそれらが協力してWebページのレンダリングと相互作用を駆動する方法を学びます。私たちは皆、JavaScriptとブラウザの関係を知っています。 JavaScriptは、フロントエンド開発のコア言語です。ブラウザで直接実行され、Webページが鮮明で興味深いものになります。なぜJavascrを疑問に思ったことがありますか

node.jsは、主にストリームのおかげで、効率的なI/Oで優れています。 ストリームはデータを段階的に処理し、メモリの過負荷を回避します。大きなファイル、ネットワークタスク、リアルタイムアプリケーションの場合。ストリームとTypeScriptのタイプの安全性を組み合わせることで、パワーが作成されます

PythonとJavaScriptのパフォーマンスと効率の違いは、主に以下に反映されています。1)解釈された言語として、Pythonはゆっくりと実行されますが、開発効率が高く、迅速なプロトタイプ開発に適しています。 2)JavaScriptはブラウザ内の単一のスレッドに限定されていますが、マルチスレッドおよび非同期I/Oを使用してnode.jsのパフォーマンスを改善でき、両方とも実際のプロジェクトで利点があります。

JavaScriptは1995年に発信され、Brandon Ikeによって作成され、言語をCに実現しました。 2。JavaScriptのメモリ管理とパフォーマンスの最適化は、C言語に依存しています。 3. C言語のクロスプラットフォーム機能は、さまざまなオペレーティングシステムでJavaScriptを効率的に実行するのに役立ちます。

JavaScriptはブラウザとnode.js環境で実行され、JavaScriptエンジンに依存してコードを解析および実行します。 1)解析段階で抽象的構文ツリー(AST)を生成します。 2)ASTをコンパイル段階のバイトコードまたはマシンコードに変換します。 3)実行段階でコンパイルされたコードを実行します。

PythonとJavaScriptの将来の傾向には、1。Pythonが科学コンピューティングの分野での位置を統合し、AI、2。JavaScriptはWebテクノロジーの開発を促進します。どちらもそれぞれのフィールドでアプリケーションシナリオを拡大し続け、パフォーマンスをより多くのブレークスルーを行います。

開発環境におけるPythonとJavaScriptの両方の選択が重要です。 1)Pythonの開発環境には、Pycharm、Jupyternotebook、Anacondaが含まれます。これらは、データサイエンスと迅速なプロトタイピングに適しています。 2)JavaScriptの開発環境には、フロントエンドおよびバックエンド開発に適したnode.js、vscode、およびwebpackが含まれます。プロジェクトのニーズに応じて適切なツールを選択すると、開発効率とプロジェクトの成功率が向上する可能性があります。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

DVWA
Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、

MantisBT
Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

SecLists
SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

PhpStorm Mac バージョン
最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ホットトピック









