もう一度理解する、JavaScriptの配列とコピー #JavaScript - Qiita
上記を読んでみます。
まず、これです。
『const a = [1, 2, 3];
const b = a; // aの「コピー」??
これはコピーではない』
JavaScriptでは(この言語に限らず)、数学の『=』と、プログラミング言語の『=』が違うということが根底にあります。どうしてもわかりやすくするために、初めの説明では、『値を代入する』という言葉で説明しがちなのでこのような混同が起こるのは避けられません。
データ格納庫(ストレージ)内に、名前を付けてその空間を確保し、そこに、オブジェクトそのものあるいは、いろいろ処理した後返ってきたオブジェクトが入るようにしており、それを紐づけているのが、『=』です。
よく片付けなどで、『物の住所をきめる』ことがコツなどと言いますが、それと類似しております。
また、次のような文章が出てきます。
『配列はオブジェクトです。(一部改変)
(中略)
配列をコピーすると言った場合、「同じ要素を持っているが別オブジェクトであるような新しい配列を作る」ことを意味する、と考えることができます。』
ほかに、浅いコピーと深いコピーという話が出てきます。
一次元配列の場合は、あまりこれは問題にならないようです。二次元配列を扱う場合などに問題になるようです。これについてはここでは触れません。
もともとバニラjavascriptでも、あまり concat( )は使用せず、push()一筋でしたので、React.jsでuseStateで配列を扱う場合に違和感を感じました。
『push(x)
とconcat(x)
はともに、「配列の末尾に要素x
を付け加える」という操作ですが、push
では配列の内容が変化しているのに対して、concat
では新しい配列が返され、元の配列は変更されていないことに注意してください。』
手を使って考えてみましょう。
const a = [123, 456, 789 ];
const b = a;
console.log(b[0]); → 123と表示される
console.log(b[1]); → 456と表示される
console.log(b[2]); → 789と表示される
これは、[123, 456, 789]という配列のために、データ格納庫(ストレージ)内で、aという名前の空間と、bという名前の空間を二つも用意していることになります。
バニラJavaScirptで、
b[0]= 901; とした場合は、 bという名前の空間にはいってる配列は、当然
[901, 456, 789]ですが、
aという名前の空間にはいっている配列も、同様に[901, 456, 789]になってます。
ただし、配列をコピーすると言った場合、「同じ要素を持っているが別オブジェクトであるような新しい配列を作る」ことを意味するので、
その場合は、ES2015以降であれば、簡単に下記のように書けます。
const c = [...a]
これを、スプレッド構文といいます。
それ以前はどうしていたのでしょうか?
空配列で定義しておいて、for文で配列の各要素を、push( )で詰め込んでいっていたのでしょう。それと比べるとはるかにラクです。
バニラJavaScirptで、
a[0] = 901; としても、
c[0] は 123のままです。逆も然りです。
各要素の値は同じだが、物理的に(?)別の配列ができたことになります。
では、本題に移り、React.jsで、useStateで配列を扱うときはどうなるでしょうか?
useStateで配列要素を追加・削除・変更する方法 #JavaScript - Qiita
export default function App() {
const [fruits, setFruits] = useState(['りんご', 'バナナ', 'いちご']) ;
const addFruits = ( ) => {
setFruits([...fruits, 'ドリアン']) ;
console.log(fruits) ;
}
return(
<div>
<button onClick={ addFruits }>ドリアンを追加</button>
</div>
) ;
}
というような感じになるのでしょう。