JavaScript ディープ コピーは、初心者だけでなく経験豊富な開発者でもよく遭遇する問題であり、JavaScript ディープ コピーをよく理解できません。
ディープコピー(deepClone)?
深いコピーの反対は浅いコピーです。多くの初心者はこの概念に触れると非常に混乱します。
ディープコピーを使用する理由は何ですか?
多くの場合、変数に値を代入し、メモリアドレスに値を代入する必要がありますが、参照値型を代入する場合、メモリ領域を共有するだけなので、代入は以前のものと一貫性が保たれます。価値。 。
具体的な例を見てみましょう
// 给test赋值了一个对象 var test = { a: 'a', b: 'b' }; // 将test赋值给test2 // 此时test和test2是共享了同一块内存对象,这也就是浅拷贝 var test2 = test; test2.a = 'a2'; test.a === 'a2'// 为true
イラスト:
これで、参照値型データが相互に影響を与える理由を簡単に理解できます。
実装
ディープコピー関数を実装するには、JavaScriptの数値型について話し合う必要があります。
JavaScriptの型を決定する
JavaScriptには次の基本的な型があります
型の説明
unknown未定義の型には、値が1つだけあります。未定義は、変数に値が割り当てられていない場合の値です
null null型も空のオブジェクト参照である null 値が 1 つだけあります
Boolean Boolean には true と false の 2 つの値があります
String テキスト情報を表します
Number 数値情報を表します
Object 関数や関数を含む一連の属性の順序付けされていないコレクションですarray 配列
typeof では判定できません 関数や配列については、ここでは Object.prototype.toString メソッドを使用します。
[デフォルトでは、各オブジェクトは Object から toString() メソッドを継承します。このメソッドがオブジェクト自体またはより上位のプロトタイプの同じ名前のメソッドによってオーバーライド (シャドウ) されていない場合、オブジェクトの toString() が呼び出されます。 ) メソッドは "[オブジェクト タイプ]" を返します。ここでの文字列タイプはオブジェクト タイプを表します][1]
function type(obj) { var toString = Object.prototype.toString; var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; return map[toString.call(obj)]; }
deepClone の実装
非参照値タイプの値、直接代入、および参照値タイプの場合(オブジェクト) を再度走査し、再帰的に割り当てる必要があります。
function deepClone(data) { var t = type(data), o, i, ni; if(t === 'array') { o = []; }else if( t === 'object') { o = {}; }else { return data; } if(t === 'array') { for (i = 0, ni = data.length; i < ni; i++) { o.push(deepClone(data[i])); } return o; }else if( t === 'object') { for( i in data) { o[i] = deepClone(data[i]); } return o; } }
ここで注意すべき点があります。関数の種類について、ここのブロガーは値を直接割り当てるか、メモリ値を共有します。これは、関数が入力値と戻り値を持つ特定の関数を完了することに重点があり、上位レベルのビジネスにとってはビジネス関数を完了することに重点があり、関数を実際にディープ コピーする必要がないためです。
しかし、関数の型をコピーするにはどうすればよいでしょうか?
実際、ブロガーは new を使用して操作することしか考えていませんでしたが、関数は 1 回実行されます。実行結果がどうなるかは想像できません。 o(╯□╰)o!他に良いアイデアはまだないので、皆さんのご指導大歓迎です!
この時点で、ディープコピーはほぼ実装されていますが、シャローコピーはまだ実装されていないと思う人はいますか?
浅いコピーですか?
シャローコピーの場合は、共通メモリ領域を操作するだけと理解できます!ここには危険が潜んでいるでしょう! (.﹏.*)
この共有データを制御せずに直接操作すると、頻繁にデータ異常が発生し、他の部分によってデータが変更されてしまいます。したがって、データ ソースを直接操作するのではなく、データ ソースでデータに対して CURD 操作を実行するためのいくつかのメソッドをカプセル化する必要があります。
おそらくここでほぼ完成ですが、フロントエンドとしては JavaScript 自体だけでなく、DOM やブラウザなども考慮する必要があります。
要素の型
次のコードを見てください。何が返されるでしょうか?
Object.prototype.toString.call(document.getElementsByTagName('div')[0])
答えは、[object HTMLDivElement]です
時々、dom 要素を保存して、誤って深いコピーを作成してしまうことがあります。 Element 要素に対する判断力が欠けています。 Element要素を判定するにはinstanceofを使用して判定します。異なるタグの場合、tostring は異なるタグに対応するコンストラクターを返すためです。
function type(obj) { var toString = Object.prototype.toString; var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; if(obj instanceof Element) { return 'element'; } return map[toString.call(obj)]; }
最初に JSON.stringify を渡し、次に JSON.parse を渡してディープ コピーを実現します。ただし、データ型は基本的な数値型のみをサポートします。
var obj = { a: 'a', b: function(){console.log('b')} } //在JSON.stringify的时候就会把function给过滤了。 JSON.stringify(obj)// "{"a":"a"}"
概要
ディープコピーの概要とディープコピーの実装方法について説明します。さまざまなシナリオで、ビジネス シナリオに基づいてディープ コピーを使用する必要があるかどうかを判断する必要があります。
JavaScript ディープコピー (deepClone) 関連記事の詳細については、PHP 中国語 Web サイトに注目してください。