JavaScript 再入門 配列コピー
JavaScriptの配列・オブジェクトのコピーはちょっとややこしいです。
業務のコードでも間違った(もしくは考慮されていない)使い方をしているのを見かけるし、
自分も脳筋 ...
or _.cloneDeep
は良くないので今一度思考を整理したいと思います。
コピーの種類
JavaScriptのコピーでは第一レベルまでコピーする浅いコピー(Shallow Copy)とネストしたオブジェクトまでコピーする2つのコピーがあります。
この第一階層までってのが肝で、 concatはダメでspreadは大丈夫。みたいな主張をたまに聞く結果となります。第一階層とは以下のようなネストしてない配列となります。
let family = ['わい', '弟', '妹', 'おとん', 'おかん', ['嫁', '義妹']]; let newFamily = []; // 配列処理 newFamily = [...family]; newFamily[0] = 'ぼく'; newFamily[5][0] = 'ぼく嫁'; console.log(family); console.log(newFamily); // 結果 [ 'わい', '弟', '妹', 'おとん', 'おかん', [ 'ぼく嫁', '義妹' ] ] [ 'ぼく', '弟', '妹', 'おとん', 'おかん', [ 'ぼく嫁', '義妹' ] ] // ネストした配列はメモリ参照となる
それでいてJavaScriptではコピーできる方法が多いので、それが理解の妨げに拍車をかけてる気がします。
浅すぎるコピー
同じ参照を持つ。コピー用途で使ってたらしばくやつです。
let family = ['わい', '弟', '妹', 'おとん', 'おかん', ['嫁', '義妹']]; let newFamily = family;
浅いコピー
第一階層までは完全に別の
Array.from(['a', 'b', 'c']);
配列風オブジェクトや反復可能オブジェクトから、新しい、浅いコピーの Array インスタンスを生成します。 ここでは省きますが、配列風というのが特徴
let family = ['わい', '弟', '妹', 'おとん', 'おかん', ['嫁', '義妹']]; // 配列を複製 let newFamily = Array.from(family);
Array.from() - JavaScript | MDN
['a', 'b', 'c'].slice(1, 2)
begin から end まで選択された配列の一部をシャローコピーして、新しい配列オブジェクトを返します。
名前の通り切り出し箇所をbeginとendで指定できるのがポイント
let family = ['わい', '弟', '妹', 'おとん', 'おかん', ['嫁', '義妹']]; // 配列を複製 let newFamily = arr.slice(2,4);
Array.prototype.slice() - JavaScript | MDN
spread構文
ES6から入ったあれ
スプレッド構文を使うと、配列式や文字列などの反復可能オブジェクトを、 0 個以上の引数 (関数呼び出しの場合) や要素 (配列リテラルの場合) を期待された場所で展開したり、オブジェクト式を、 0 個以上のキーと値のペア (オブジェクトリテラルの場合) を期待された場所で展開したりすることができます。
airbも配列コピーに推奨している。確かに配列のみならスプレッドは確かにわかりやすいか〜
let family = ['わい', '弟', '妹', 'おとん', 'おかん', ['嫁', '義妹']]; // 配列を複製 let newFamily = [...family];
spread構文はこの使い方が最強。
const numbers = [1, 2, 3]; const str = "abc"; console.log([...numbers, ...str])); // 6
深いコピー
ネストした階層まで完全に別オブジェクトを作りだす深いコピーです。 シャローコピーよりはコストがかかるのでネストをしないなら不要。
JSON.parse(JSON.stringify([1, 2, 3]))
昔からあるTips。Date型が上手く変換できなかったかも。完全にコピーするなら _.cloneDeep
が良いかなぁ。
let family = ['わい', '弟', '妹', 'おとん', 'おかん', ['嫁', '義妹']]; let newFamily = JSON.parse(JSON.stringify(family));
_.cloneDeep
現在最強ディープコピー。lodash
の一関数遅いと聞くので、もっと早いものがあれば是非...
const _ = require('lodash'); let family = ['わい', '弟', '妹', 'おとん', 'おかん', ['嫁', '義妹']]; let newFamily = _.cloneDeep(family);
TODO: _.cloneDeepの詳細を追う
所感
シャローコピーならスプレッド、ディープコピーなら _.cloneDeep
各種メソッドの整理になってよかったです。良いJavaScriptライフを
1日1コミット
JS_Study/array_copy.js at b820b5d77376ed70c005b86363c0b0ff4c45b9d8 · gonta616/JS_Study · GitHub