JavaScriptでは、ディープコピーテクニックは配列の要素に依存します。そこから始めましょう。
3種類の要素
要素は、リテラル値、リテラル構造、またはプロトタイプです。
// Literal values (type1)
const booleanLiteral = true;
const numberLiteral = 1;
const stringLiteral = 'true';
// Literal structures (type2)
const arrayLiteral = [];
const objectLiteral = {};
// Prototypes (type3)
const booleanPrototype = new Bool(true);
const numberPrototype = new Number(1);
const stringPrototype = new String('true');
const arrayPrototype = new Array();
const objectPrototype = new Object(); // or `new function () {}`
これらの要素から、3種類の配列を作成できます。
// 1) Array of literal-values (boolean, number, string)
const type1 = [true, 1, "true"];
// 2) Array of literal-structures (array, object)
const type2 = [[], {}];
// 3) Array of prototype-objects (function)
const type3 = [function () {}, function () {}];
ディープコピーテクニックは3つのアレイタイプに依存します
配列の要素のタイプに基づいて、さまざまな手法を使用してディープコピーを作成できます。
リテラル値(TYPE1)のアレイ、、、及び技術は、リテラル値(ブール値、数値、文字列)のみを有するディープコピーアレイに使用することができます。ここで、Spreadオペレーターは最高のパフォーマンスを発揮します(https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat)。
[...myArray]
myArray.splice(0)
myArray.slice()
myArray.concat()
[...myArray]
リテラル値(type1)およびリテラル構造(type2)
の配列このJSON.parse(JSON.stringify(myArray))
手法は、リテラル値(ブール値、数値、文字列)およびリテラル構造(配列、オブジェクト)のディープコピーに使用できますが、プロトタイプオブジェクトには使用できません。
すべての配列(type1、type2、type3)
jQuery $.extend(myArray)
手法を使用して、すべての配列型をディープコピーできます。UnderscoreやLo-dashなどのライブラリは、jQuery と同様のディープコピー機能を提供しますが$.extend()
、パフォーマンスは低下します。さらに驚くべきことに、http://jsperf.com/js-deep-copy/15$.extend()
のJSON.parse(JSON.stringify(myArray))
手法よりもパフォーマンスが優れています。
また、サードパーティのライブラリ(jQueryなど)を避けている開発者には、次のカスタム関数を使用できます。$ .extendよりもパフォーマンスが高く、すべての配列をディープコピーします。
function copy(aObject) {
if (!aObject) {
return aObject;
}
let v;
let bObject = Array.isArray(aObject) ? [] : {};
for (const k in aObject) {
v = aObject[k];
bObject[k] = (typeof v === "object") ? copy(v) : v;
}
return bObject;
}
質問に答えるために...
質問
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2は、arr1と同じ配列を指し、新しい独立した配列ではないことに気付きました。配列をコピーして2つの独立した配列を取得するにはどうすればよいですか?
回答
arr1
はリテラル値(ブール値、数値、または文字列)の配列なので、spread演算子...
が最高のパフォーマンスを発揮する、上記で説明した任意のディープコピー手法を使用できます。
// Highest performance for deep copying literal values
arr2 = [...arr1];
// Any of these techniques will deep copy literal values as well,
// but with lower performance.
arr2 = arr1.slice();
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = $.extend(true, [], arr1); // jQuery.js needed
arr2 = _.extend(arr1); // Underscore.js needed
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = copy(arr1); // Custom-function needed - as provided above
slice
、splice
操作と新しいスプレッドオペレーターのパフォーマンスが優れており、Array.from
実装がはるかに遅いようです。見perfjs.fnfo