可変タイプとストレージスペーススタックメモリとヒープメモリ基本的なデータ型文字列、数値、null、未定義、ブール値、シンボル(ES6 の新機能)変数の値はスタック メモリに保存され、変数の値に直接アクセスして変更できます。基本データ型にはコピーがないため、たとえば、1 の値を変更することはできません。 参照タイプオブジェクト 関数 RegExp 数学 日付 値はオブジェクトであり、ヒープ メモリに格納されます。スタック メモリ内の変数には、ヒープ メモリ内の対応するアドレスへのポインタが格納されます。 グラフィックストレージスペースlet a1 = 0; // スタックメモリ let a2 = "this is string" // スタックメモリ let a3 = null; // スタックメモリ let b = { x: 10 }; // 変数 b はスタックに存在し、{ x: 10 } はヒープ内のオブジェクトとして存在します let c = [1, 2, 3]; // 変数 c はスタックに存在し、[1, 2, 3] はヒープ内のオブジェクトとして存在します 参照タイプの割り当てa = {x: 10, y: 20}とします。 b = a とします。 5 倍 コンソールログ(ax); // 5 ディープコピーとシャローコピーディープコピーオブジェクトをメモリから完全にコピーし、ヒープメモリ内に新しい領域を開いて新しいオブジェクトを格納し、新しいオブジェクトを変更しても元のオブジェクトには影響しません。 浅いコピー浅いコピーはオブジェクトのビット単位のコピーであり、元のオブジェクトのプロパティ値の正確なコピーを持つ新しいオブジェクトを作成します。属性がプリミティブ型の場合はプリミティブ型の値がコピーされ、属性がメモリ アドレス (参照型) の場合はメモリ アドレスがコピーされます。 オブジェクトの割り当てオブジェクトを新しい変数に割り当てる場合、実際に割り当てられるのはヒープ内のデータではなく、スタック内のオブジェクトのアドレスです。つまり、2 つのオブジェクトは同じストレージ スペースを指します。どちらのオブジェクトが変更されても、実際に変更されるのはストレージ スペースの内容です。したがって、2 つのオブジェクトはリンクされています。 3つの比較浅いコピーの5つの一般的な方法オブジェクト.assign()Object.assign() メソッドは、ソース オブジェクト自身の列挙可能なプロパティを任意の数だけターゲット オブジェクトにコピーし、ターゲット オブジェクトを返すことができます。しかしObject.assign()は浅いコピーを実行する Object.assignはソースオブジェクト(sources)のすべてのプロパティを左から右に走査し、=を使用してターゲットオブジェクト(target)に割り当てます。 var obj = { a: {a: "kobe", b: 39},b:1 }; var initalObj = Object.assign({}, obj); initalObj.aa = "ウェイド"; 初期オブジェクトb = 2; console.log(obj.aa); //ウェイド コンソールログ(obj.b); //1 スプレッド演算子obj = {a:1,b:{c:1}}とします。 obj2 = {...obj} とします。 2 番目の引数は 0 です。 console.log(obj); //{a:2,b:{c:1}} コンソールログ(obj2); //{a:1,b:{c:1}} obj.bc = 2; console.log(obj); //{a:2,b:{c:2}} コンソールログ(obj2); //{a:1,b:{c:2}} 配列.プロトタイプ.スライスslice() メソッドは、begin と end (end を除く) によって決定される元の配列の浅いコピーである新しい配列オブジェクトを返します。元の配列の基本型は変更されませんが、参照型は変更されます。 arr = [1, 3, { ユーザー名: 'kobe' }]; arr3 = arr.slice() とします。 0 は 0 です。 arr3[2].ユーザー名 = 'ウェイド' コンソールにログ出力します。 配列.プロトタイプ.連結()arr = [1, 3, { ユーザー名: 'kobe' }]; arr2=arr.concat() とします。 0 は 0 です。 arr2[2].ユーザー名 = 'ウェイド'; コンソールにログ出力します。 手書きの浅いコピー関数 shallowCopy(src) { var dst = {}; (var prop in src) の場合 { src.hasOwnProperty(prop) の場合 { dst[prop] = src[prop]; } } dst を返します。 } ディープコピーの一般的な方法jsON.parse(jsON.stringify())JSON.stringifyを介してディープコピーを実装する際には、いくつか注意すべき点があります。 コピーされたオブジェクトの値に関数、未定義、またはシンボルが含まれている場合、JSON.stringify() によってシリアル化された JSON 文字列ではキーと値のペアが消えます。 列挙不可能なプロパティをコピーできません。オブジェクトのプロトタイプ チェーンをコピーできません。 日付参照型をコピーすると文字列になる RegExp参照型をコピーすると空のオブジェクトが生成されます オブジェクトにNaN、Infinity、-Infinityが含まれている場合、シリアル化された結果はnullになります。 ループ内でオブジェクトをコピーできません (例: obj[key] = obj) arr = [1, 3, { ユーザー名: 'kobe' }]; arr4 = JSON.parse(JSON.stringify(arr)) とします。 arr4[2].ユーザー名 = 'ダンカン'; コンソールログ(arr, arr4) 手書きの乞食版ディープコピーまず、この deepClone 関数は列挙できないプロパティとシンボル型をコピーできません。 ここでは、ループ反復はオブジェクト参照型の値に対してのみ実行され、配列、日付、正規表現、エラー、関数参照型は正しくコピーできません。 オブジェクトがループしている、つまり循環参照になっている(例:obj1.a = obj) 関数クローン(ターゲット) { if (typeof target === 'object') { cloneTarget を Array.isArray(target) とします。[] : {}; for (const キー in ターゲット) { cloneTarget[キー] = clone(target[キー]); } cloneTarget を返します。 } それ以外 { ターゲットを返します。 } }; 皇帝版ディープコピーこの例は ConardLi の github からのもので、ソース アドレスは https://github.com/ConardLi/ です。 const mapTag = "[オブジェクト Map]"; const setTag = "[オブジェクト Set]"; const arrayTag = "[オブジェクト配列]"; const objectTag = "[オブジェクト オブジェクト]"; const argsTag = "[オブジェクト引数]"; const boolTag = "[オブジェクト ブール値]"; const dateTag = "[オブジェクト Date]"; const numberTag = "[オブジェクト番号]"; const stringTag = "[オブジェクト文字列]"; const symbolTag = "[オブジェクト シンボル]"; const errorTag = "[オブジェクト Error]"; const regexpTag = "[オブジェクト RegExp]"; const funcTag = "[オブジェクト関数]"; const deepTag = [mapTag、setTag、arrayTag、objectTag、argsTag]; 関数 forEach(配列, iteratee) { インデックスを -1 とします。 定数長さ = 配列.長さ; (++インデックス < 長さ) の間 { iteratee(配列[インデックス], インデックス); } 配列を返します。 } 関数isObject(ターゲット) { const type = typeof ターゲット; 戻りターゲット !== null && (type === "オブジェクト" || type === "関数"); } 関数 getType(ターゲット) { Object.prototype.toString.call(target) を返します。 } 関数 getInit(ターゲット) { const Ctor = target.constructor; 新しい Ctor() を返します。 } 関数 cloneSymbol(ターゲット) { Object(Symbol.prototype.valueOf.call(target)) を返します。 } 関数 cloneReg(ターゲット) { const reFlags = /\w*$/; const 結果 = 新しい targe.constructor(targe.source、reFlags.exec(targe)); 結果.lastIndex = ターゲット.lastIndex; 結果を返します。 } 関数 cloneFunction(func) { 定数 bodyReg = /(?<={)(.|\n)+(?=})/m; 定数paramReg = /(?<=\().+(?=\)\s+{)/; 定数 funcString = func.toString(); if (関数プロトタイプ) { 定数パラメータ = paramReg.exec(funcString); bodyReg は、次のコードで定義されます。 if (本文) { if (パラメータ) { param[0]を分割します。 新しい関数(...paramArr、body[0])を返します。 } それ以外 { 新しい関数(body[0])を返します。 } } それ以外 { null を返します。 } } それ以外 { eval(funcString) を返します。 } } 関数 cloneOtherType(ターゲット, タイプ) { const Ctor = target.constructor; スイッチ(タイプ){ ケース boolタグ: ケース番号タグ: ケース文字列タグ: ケースエラータグ: ケース日付タグ: 新しい Ctor(target) を返します。 case regexpタグ: cloneReg(ターゲット)を返します。 ケースシンボルタグ: cloneSymbol(target) を返します。 ケース関数タグ: cloneFunction(ターゲット) を返します。 デフォルト: null を返します。 } } 関数クローン(ターゲット、マップ = 新しいWeakMap()) { // 元の型を複製する if (!isObject(target)) { ターゲットを返します。 } // 初期化 const type = getType(target); cloneTarget を作成します。 deepTag.includes(type) の場合 cloneTarget = getInit(ターゲット、タイプ); } それ以外 { cloneOtherType(ターゲット、タイプ) を返します。 } // 循環参照を防ぐ if (map.get(target)) { map.get(target) を返します。 } マップを設定します(ターゲット、クローンターゲット); // セットを複製する if (type === setTag) { ターゲット.forEach(値 => { cloneTarget.add(clone(値、マップ)); }); cloneTarget を返します。 } // マップを複製する if (type === mapTag) { target.forEach((値, キー) => { cloneTarget.set(キー、clone(値、マップ)); }); cloneTarget を返します。 } // オブジェクトと配列を複製します。const keys = type === arrayTag ? undefined : Object.keys(target); forEach(キー || ターゲット、(値、キー) => { if (キー) { キー = 値; } cloneTarget[key] = clone(target[key], map); }); cloneTarget を返します。 } 定数マップ = 新しい Map(); map.set("キー", "値"); map.set("ConardLi", "code Secret Garden"); set は新しい Set() です。 set.add("ConardLi"); set.add("コード秘密の庭"); 定数ターゲット = { フィールド1: 1, フィールド2: 未定義、 フィールド3: { 子供: 「子供」 }, フィールド4: [2, 4, 8], 空: null、 地図、 セット、 bool: 新しいブール値(true)、 num: 新しい数値(2)、 str: 新しい文字列(2)、 シンボル: オブジェクト(シンボル(1))、 日付: 新しい Date(), reg: /\d+/, エラー: 新しい Error()、 関数1: () => { console.log("コード秘密の庭"); }, 関数2: 関数(a, b) { a + b を返します。 } }; const 結果 = clone(ターゲット); console.log(ターゲット); console.log(結果); 以上がJS変数ストレージのディープコピーとシャローコピーの詳しい説明です。JS変数ストレージのディープコピーとシャローコピーの詳細については、123WORDPRESS.COMの他の関連記事に注目してください! 以下もご興味があるかもしれません:
|
<<: MySQL コマンドラインでよく使われる 18 個のコマンド
>>: Linux ユーザー状態とカーネル状態間の通信方法の詳細な説明
目次ノードのバージョンが一致しない、ノードをアップグレードまたはダウングレードするnvm を使用して...
目次問題の説明レンダリング3種類のコード要約する問題の説明通常、表のヘッダーは折り返されませんが、ビ...
Docker をインストールし、Docker コアとインストールを通じて簡単な操作を実行できます。 ...
背景同社のサーバーはすべて Alibaba Cloud ECS ホストを購入しています。デフォルトの...
環境説明サーバーシステム: Ubuntu 18.04 64ビットnginx: 1.14この記事では主...
1. はじめに少し前、開発者がテスト環境や本番環境で誤った操作をし、データベースを誤って削除/更新し...
目次1. ストアドプロシージャ1.1. 基本構文1.2 実行権限を指定してストアドプロシージャを作成...
序文デモでは古いバージョンのブラウザのグラデーションが実装されています[IE9-]。 IE9 より前...
この記事では、例を使用して、MySQL で効率的なインデックスを作成する方法について説明します。ご参...
この記事では、参考までに、テキストループスクロールを実現するアプレットの具体的なコードを例を挙げて紹...
問題を見つける最近、プロジェクトで問題が発生しました。接続が多すぎるため、「接続が多すぎます」という...
目次方法1 1. 構成とインストールの手順:方法2方法3要約する方法1 1. 構成とインストールの手...
不明な点があるときはいつでも、Blog Park にアクセスして、いつでも答えやインスピレーションを...
このチュートリアルの動作環境: Windows 7 システム、vue 2.9.6 バージョン、DEL...
a タグが新しいページを開くかどうか: (1)百度百科事典:ヘッダーが異なる場合は新しいページが開き...