目次
str
引用データのコピー
JSON.parse()
3.2 Object.assign()
4.1 浅拷贝
4.2 深拷贝
ホームページ ウェブフロントエンド jsチュートリアル JavaScript トピック 5: 深いコピーと浅いコピー

JavaScript トピック 5: 深いコピーと浅いコピー

Mar 08, 2021 am 09:36 AM
javascript

JavaScript トピック 5: 深いコピーと浅いコピー

#コピーのプロセスを理解して不要なミスを回避しましょう。Js 特別シリーズの深いコピーと浅いコピーを一緒に頑張りましょう~

目次

    1. コピー例
  • 2. 浅いコピー
  • 3. 深いコピーの方法は?
  • 4. 深いコピーと浅いコピーを自分で実装する

無料学習の推奨事項: javascriptビデオチュートリアル

1. 例をコピー

#データを操作すると、次のような状況が発生する可能性があります:

    データのセットは頻繁に変更されますが、元のデータが使用される可能性があります
  1. 同じデータのセットが 2 つ必要ですが、1 つを変更したくないので、もう 1 つが変更されます
  2. #I 手術前後のデータを比較する必要があります
  3. #…
  4. 同じようなニーズのシナリオに遭遇したとき、最初に思い浮かぶのは次のようなことです。コピーすることはできますが、コピーすることにも多くの知識が必要であることは知りません~
次の簡単な例に聞き覚えはありますか?

1.1 基本型のコピー例

var str = 'How are you';var newStr = str;newStr = 10console.log(str); // How are youconsole.log(newStr); // 10
ログイン後にコピー
誰もが想像できるように、string は基本型であり、その値はスタックに格納されます。これをコピーすると、実際には新しい変数が開かれます。新しい空間。
str

newStr は、レイアウトは同じですが接続されていない 2 つの同一の部屋のようなものです。 1.2 参照型のコピー例

var data = [1, 2, 3, 4, 5];var newData = data;newData[0] = 100;console.log(data[0]); // 100console.log(newData[0]); // 100
ログイン後にコピー
同様のコードセグメントですが、今回は配列の参照型を例として使用します。割り当てられたデータを変更すると、元のデータが変化していることがわかります。これは明らかに私たちのニーズを満たしていません。この記事では、
引用データのコピー
に関する知識について説明します。

J のデータ型について質問がある場合は、「JavaScript の基本データ型」を参照してください。

JavaScript トピック 5: 深いコピーと浅いコピー2. 浅いコピー

コピーの分割は参照型に基づいて説明されます。浅いコピー - 名前が示すように、浅いコピーは「浅いコピー」です。表面的な作業のみを行います:

var arr = [1, 2, 3, 4];var newArr = arr;console.log(arr, newArr); // [1,2,3,4] [1,2,3,4]newArr[0] = 100;console.log(arr, newArr) // [100,2,3,4] [100,2,3,4]
ログイン後にコピー
幸いなことに、何も起こりません (操作) 新しい配列が操作されると、両方の変数に格納されているデータが変更されます。

このような状況が発生する理由は、

参照型

の基本的な特性によるものでもあります。

変数に格納される値はポインタ ( point)、ストレージを指すオブジェクトのメモリ アドレス。新しい変数に値を割り当てることは、新しいキーを割り当てることと同じであり、部屋は変更されません。

  • 配列のスライスと連結は両方とも新しい配列を返します。一緒に試してみましょう:
var arr = [1,2,3,4];var res = arr.slice();// 或者res = arr.concat()res[0] = 100;console.log(arr); // [1,2,3,4]
ログイン後にコピー
この問題はすぐに解決しましたか?このデータ層はこのように処理されるため、確かに問題は解決されますが、しかし!

var arr = [ { age: 23 }, [1,2,3,4] ];var newArr = arr.concat();arr[0].age = 18;arr[1][0] = 100;console.log(arr) // [ {age: 18}, [100,2,3,4] ]console.log(newArr) // [ {age: 18}, [100,2,3,4] ]
ログイン後にコピー
確かに、物事はそれほど単純ではありません。これは、データ型が異なるためでもあります。

S メモリ内のアドレスを直接操作することは許可されていないため、オブジェクトのメモリ空間を操作できないため、オブジェクトに対する操作はその参照に対してのみ操作されます。

効率

の原則に従って、

浅いコピー

では私たちの要件を満たせないため、##の達成を手伝ってくれる人がいるかどうかを探しています。 #ディープコピー メソッド。

#3. ディープコピーをするにはどうすればよいですか?

JavaScript トピック 5: 深いコピーと浅いコピー

データ メソッドが失敗しました。他に方法はありますか?独立したデータの真のコピーを作成する必要があります。

3.1 JSON

ここでは、最も簡潔な処理を実現するために、JSON の 2 つのメソッド

JSON.stringify()

JSON.parse()
を使用します。ディープ コピー

var arr = ['str', 1, true, [1, 2], {age: 23}]var newArr = JSON.parse( JSON.stringify(arr) );newArr[3][0] = 100;console.log(arr); // ['str', 1, true, [1, 2], {age: 23}]console.log(newArr); // ['str', 1, true, [100, 2], {age: 23}]
ログイン後にコピー
この方法はディープ コピーを実装する最も簡単な方法のはずですが、まだ問題があります。今行ったことを見てみましょう:

すべての型を含む配列を定義しますarr

    JSON.stringify(arr)、JavaScript オブジェクトまたは値を
  1. JSON 文字列に変換します
  2. JSON.parse(xxx) メソッドは、JSON 文字列を解析し、文字列で記述された
  3. 値またはオブジェクトを構築するために使用されます。
  4. 理解 :
元のデータを

new string に変換し、new string

## を介して

new object# に復元するという変更方法であることがわかります。データ型はオブジェクト参照のコピープロセスを間接的にバイパスし、元のデータには影響を与えません。 制限事項: このメソッドの基本的な目的は、「転送」中のデータの整合性を確保することであり、

JSON.stringify()

対応する JSON 形式 :

への値の変換にも欠陥があります
  • undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。
  • 函数、undefined 被单独转换时,会返回 undefined,
    • 如JSON.stringify(function(){})
    • JSON.stringify(undefined)
  • 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
  • NaN 和 Infinity 格式的数值及 null 都会被当做 null。
  • 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。

所以当我们拷贝函数、undefined等stringify转换有问题的数据时,就会出错,我们在实际开发中也要结合实际情况使用。

举一反三:

既然是通过改变数据类型来绕过拷贝引用这一过程,那么单纯的数组深拷贝是不是可以通过现有的几个API来实现呢?

var arr = [1,2,3];var newArr = arr.toString().split(',').map(item => Number(item))newArr[0] = 100;console.log(arr); // [1,2,3]console.log(newArr); // [100,2,3]
ログイン後にコピー

注意,此时仅能对包含纯数字的数组进行深拷贝,因为:

  1. toString无法正确的处理对象和函数
  2. Number无法处理 false、undefined等数据类型

但我愿称它为纯数字数组深拷贝

JavaScript トピック 5: 深いコピーと浅いコピー

3.2 Object.assign()

有的人会认为Object.assign(),可以做到深拷贝,我们来看一下

var obj = {a: 1, b: { c: 2 } }var newObj = Object.assign({}, obj)newObj.a = 100;newObj.b.c = 200;console.log(obj); // {a: 1, b: { c: 200 } }console.log(newObj) // {a: 100, b: { c: 200 } }
ログイン後にコピー

神奇,第一层属性没有改变,但第二层却同步改变了,这是为什么呢?

因为 Object.assign()拷贝的是(可枚举)属性值。

假如源值是一个对象的引用,它仅仅会复制其引用值。MDN传送门

四、自己实现深浅拷贝

既然现有的方法无法实现深拷贝,不妨我们自己来实现一个吧~

4.1 浅拷贝

我们只需要将所有属性即其嵌套属性原封不动的复制给新变量一份即可,抛开现有的方法,我们应该怎么做呢?

var shallowCopy = function(obj) {
    if (typeof obj !== 'object') return;

    // 根据obj的类型判断是新建一个数组还是对象
    var newObj = obj instanceof Array ? [] : {};
    // 遍历obj,并且判断是obj的属性才拷贝
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;}
ログイン後にコピー

我们只需要将所有属性的引用拷贝一份即可~

4.2 深拷贝

相信大家在实现深拷贝的时候都会想到递归,同样是判断属性值,但如果当前类型为object则证明需要继续递归,直到最后

var deepCopy = function(obj) {
    if (typeof obj !== 'object') return;
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
        }
    }
    return newObj;}
ログイン後にコピー

我们用白话来解释一下deepCopy都做了什么

const obj = [1, { a: 1, b: { name: '余光'} } ];const resObj = deepCopy(obj);
ログイン後にコピー
  • 读取 obj,创建 第一个newObj
    • 判断类型为 []
    • key为 0 (for in 以任意顺序遍历,我们假定按正常循序遍历)
    • 判断不是引用类型,直接复制
    • key为 1
    • 判断是引用类型
    • 进入递归,重新走了一遍刚才的流程,只不过读取的是obj[1]

另外请注意递归的方式虽然可以深拷贝,但是在性能上肯定不如浅拷贝,大家还是需要结合实际情况来选择。

写在最后

JavaScript トピック 5: 深いコピーと浅いコピー

前端专项进阶系列的第五篇文章,希望它能对大家有所帮助,如果大家有什么建议,可以在评论区留言,能帮到自己和大家就是我最大的动力!

相关免费学习推荐:javascript(视频)

以上がJavaScript トピック 5: 深いコピーと浅いコピーの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 Dec 17, 2023 pm 12:09 PM

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 Dec 17, 2023 am 09:39 AM

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

JavaScriptでinsertBeforeを使用する方法 JavaScriptでinsertBeforeを使用する方法 Nov 24, 2023 am 11:56 AM

使用法: JavaScript では、insertBefore() メソッドを使用して、DOM ツリーに新しいノードを挿入します。このメソッドには、挿入される新しいノードと参照ノード (つまり、新しいノードが挿入されるノード) の 2 つのパラメータが必要です。

JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 Dec 17, 2023 am 08:41 AM

JavaScript は Web 開発で広く使用されているプログラミング言語であり、WebSocket はリアルタイム通信に使用されるネットワーク プロトコルです。 2 つの強力な機能を組み合わせることで、効率的なリアルタイム画像処理システムを構築できます。この記事では、JavaScript と WebSocket を使用してこのシステムを実装する方法と、具体的なコード例を紹介します。まず、リアルタイム画像処理システムの要件と目標を明確にする必要があります。リアルタイムの画像データを収集できるカメラ デバイスがあるとします。

See all articles