ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript配列のディープコピー解析
JavaScript の場合、配列は参照型です。concat やスライスなどの関数は浅いコピーであるため、配列をコピーする場合はよく考える必要があります。つまり、2 次元配列の場合、concat を使用してコピーすると、新しい配列を変更すると古い配列も変更されます。
そこで、グループのディープ コピーを支援するディープ コピー関数を作成したいと思いました。
通常、代入は「=」を使用して実現できます。ただし、配列、オブジェクト、関数などの参照型データの場合、このシンボルは使いにくいです。
1. 配列の単純なコピー
1.1 単純なトラバーサル
最も単純で最も基本的な方法は、当然ループ処理です。例:
JavaScript
function array_copy(arr) { var out = [], i, len; if (out[i] instanceof Array === false){ return arr; } for (i = 0, len = arr.length; i < len; i++) { if (out[i] instanceof Array){ out[i] = deepcopy(arr[i]); } else { out[i] = arr[i]; } }; return a; } //测试 var arr1 = [1, 2, 3, 4], arr2 = array_copy(arr1); console.log(arr1, arr2); arr2[2] = 10; console.log(arr1[2], arr2[2]); function array_copy(arr) { var out = [], i, len; if (out[i] instanceof Array === false){ return arr; } for (i = 0, len = arr.length; i < len; i++) { if (out[i] instanceof Array){ out[i] = deepcopy(arr[i]); } else { out[i] = arr[i]; } }; return a; } //测试 var arr1 = [1, 2, 3, 4], arr2 = array_copy(arr1); console.log(arr1, arr2); arr2[2] = 10; console.log(arr1[2], arr2[2]);
1.2 代替コピーの実装
面接の質問でよく登場するトリックは、slice メソッドまたは concat メソッドを使用することです。例:
JavaScript
var arr1 = [1, 2, 3, 4], arr2 = arr1.slice(0), arr3 = arr1.concat(); console.log(arr1, arr2, arr3); arr2[2] = 10; arr3[2] = 11; console.log(arr1[2], arr2[2], arr3[2]); var arr1 = [1, 2, 3, 4], arr2 = arr1.slice(0), arr3 = arr1.concat(); console.log(arr1, arr2, arr3); arr2[2] = 10; arr3[2] = 11; console.log(arr1[2], arr2[2], arr3[2]);
2. 配列のディープコピー
通常の 1 次元配列で値が非参照型の場合は、上記の方法を使用しても問題ありません。それ以外の場合は、もっと面倒です。ディープコピーでは、配列値がさまざまな参照型である場合を考慮する必要があります。
2.1 JSON メソッド
JSON.stringify(array) を使用してから、JSON.parse() を使用します。例:
JavaScript
var arr1 = [1, 2, [3, 4], {a: 5, b: 6}, 7], arr2 = JSON.parse(JSON.stringify(arr1)); console.log(arr1, arr2); arr2[1] = 10; arr2[3].a = 20; console.log(arr1[1], arr2[1]); console.log(arr1[3], arr2[3]); var arr1 = [1, 2, [3, 4], {a: 5, b: 6}, 7], arr2 = JSON.parse(JSON.stringify(arr1)); console.log(arr1, arr2); arr2[1] = 10; arr2[3].a = 20; console.log(arr1[1], arr2[1]); console.log(arr1[3], arr2[3]);
このメソッドには、古いブラウザとの互換性の問題があります。互換性が実際に必要な場合は、次の互換性ファイルを導入できます:
https://github.com/douglascrockford/JSON-js/blob/master/json2.js
注: 配列値が関数の場合、上記の方法はまだ機能しません。
2.2 ディープコピーの完全実装
多次元配列の入れ子や、配列の値がオブジェクトである状況を考慮すると、以下のようなプロトタイプ拡張が可能です(もちろん通常通りに書くことも可能です)関数、プロトタイプ拡張は推奨されません) :
JavaScript
Object.prototype.clone = function () { var o = {}; for (var i in this) { o[i] = this[i]; } return o; }; Array.prototype.clone = function () { var arr = []; for (var i = 0; i < this.length; i++) if (typeof this[i] !== 'object') { arr.push(this[i]); } else { arr.push(this[i].clone()); } return arr; }; //测试1 Object var obj1 = { name: 'Rattz', age: 20, hello: function () { return "I'm " + name; } }; var obj2 = obj1.clone(); obj2.age++; console.log(obj1.age); //测试2 Array var fun = function(log) {console.log}, arr1 = [1, 2, [3, 4], {a: 5, b: 6}, fun], arr2 = arr1.clone(); console.log(arr1, arr2); arr2[2][1]= 'Mike'; arr2[3].a = 50; arr2[4] = 10; console.log(arr1, arr2); Object.prototype.clone = function () { var o = {}; for (var i in this) { o[i] = this[i]; } return o; Array.prototype.clone = function () { var arr = []; for (var i = 0; i < this.length; i++) if (typeof this[i] !== 'object') { arr.push(this[i]); } else { arr.push(this[i].clone()); } return arr; //测试1 Object var obj1 = { name: 'Rattz', age: 20, hello: function () { return "I'm " + name; } var obj2 = obj1.clone(); console.log(obj1.age); //测试2 Array var fun = function(log) {console.log}, arr1 = [1, 2, [3, 4], {a: 5, b: 6}, fun], arr2 = arr1.clone(); console.log(arr1, arr2); arr2[2][1]= 'Mike'; arr2[3].a = 50; arr2[4] = 10; console.log(arr1, arr2);
2.3 jQueryのextendメソッドを使う
jQueryを使用している場合、最も簡単な方法はextendプラグインメソッドを使用することです。例:
JavaScript
var arr1 = [1, 2, [3, 4], {a: 5, b: 6}, 7], arr2 = $.extend(true, [], arr1); console.log(arr1, arr2); arr2[1] = 10; console.log(arr1, arr2); var arr1 = [1, 2, [3, 4], {a: 5, b: 6}, 7], arr2 = $.extend(true, [], arr1); console.log(arr1, arr2); arr2[1] = 10; console.log(arr1, arr2);