[図解!]JavaScriptにおける変数の"参照とコピー"[実は超重要]

# はじめに
本記事は __Udemy著者『 _CodeMafia_ 』様の「【JS】ガチで学びたい人のためのJavaScriptメカニズム」__ の内容を参考にしています。
JavaScriptの基礎的な文法から応用的な使用例まで備忘録・復習を兼ねて記事にしていこうと思います。
特にUdemy __「【JS】ガチで学びたい人のためのJavaScriptメカニズム」__ の質問内容に目を通しています。Jsの学習を共に解決していけたら幸いです。
__その他のQuiitaの記事やMDNの構文は積極的に引用しようと思います。__

## 対象読者様

+ Js入門者の方
+ Jsの参照とコピーがこんがらがって自信がない方
+ 関数の引数がうまく操れない方
+ 引数がうまく操れない方
+ Javascriptの参照の基本的な特訓をしたい方
+ ...etc

### ウォーミングアップ(プリミティブ値)
:::note info
四角い箱はメモリ空間x番地のようなものです。
:::

![スライド1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2420377/1f1834aa-1764-68e7-9ad8-98d0160794f6.jpeg)





1\. 変数aは'fugaa'という __値__ への __参照を保持している__。
2\. 変数aが参照している値が別のメモリ空間に __コピー__ される。変数bから参照が貼り直される。
3\. bに __再代入__ をした場合はbの参照先が'fugaa'から'hogebb'に変更される。

変数aが参照している'fugaa'という値自体が __コピー__ されているため(aそのものがコピーされている訳ではない)、bの値を変更してもaの値は保持されている。

:::note info
次の例で示すオブジェクトではコピーの挙動は異なってきます
:::

なんのことだか分かりにくいかもしれないので、次へ行きます。

### ウォーミングアップ(オブジェクト)
![スライド2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2420377/1d77b7e3-bd0f-1ad3-94aa-7d9036b0b173.jpeg)



1\. cからオブジェクト{}への参照が貼られ、実体({prop: OO})が別の空間に格納される。これが'propCCC'への参照を保持している状態
2\. dという変数にcを格納すると、 {}が別のメモリ空間にコピーされる。この{}の参照が保持しているのは、オブジェクトの実体であるため、この時点では d = {prop:CCC}、 
3\. d.prop = 'propDDD'とすると、元々cが{}を参照し、オブジェクトの実体を参照しているので、'propDDD'に __参照を貼り直す__ ことになる。

:::note info
 __オブジェクトを保持している変数__ を他の変数に代入した場合には、propertyを変更すると、コピー元のオブジェクトにも影響を与える。
:::


### ウォーミングアップ(オブジェクトの再代入)
![スライド3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2420377/ad6dccfc-8d79-915a-f725-f254156af43c.png)




1\. cからオブジェクト{}への参照が貼られ、実体({prop: XX})が別の空間に格納される。これが'propCCC'への参照を保持している状態
2\. dという変数にcを格納すると、 {}が別のメモリ空間にコピーされる。この{}の参照が保持しているのは、オブジェクトの実体であるため、この時点では d = {prop:CCC}、 __ここまでは上記と同じ__ 。
3\. d = {}として、dに別のオブジェクトを代入すると __参照が貼り直される__ ため、cには影響を与えない。

:::note warn
{　}への参照を切り離すか、元のオブジェクトに影響を与えるようにするか時と場合により判断するということです。次の __分割代入__ の箇所で少し深掘りします。
:::

### ウォーミングアップ(分割代入)

 __分割代入__:オブジェクトから特定のプロパティーを抽出して宣言を行う。

![スライド5.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2420377/a4fe1124-68fd-014f-c434-f77e33d4a642.jpeg)


1\. 上述と同じなので割愛。
2\. 分割代入で"prop"という新しい変数を宣言した場合、"prop"というプロパティが参照している'propA'がコピーされ、propという新しい変数がそれを参照するようになる。オブジェクトとは切り離された状況でpropという変数が宣言されている。
3\. 変数"prop"に新しい値を代入すると参照が貼り直される。

実際は関数と絡めて使うことが多いので詳しくは後に回します。




# 関数や引数が関連してきた場合

### 例1：プリミティブ値aが実引数

```javascript
let a = 0;
function f(arg) {
    arg = 1;
    console.log(a,arg); // a 0, arg 1   
}
f(a); //実行

```

この関数はプリミティブ型の変数aを引数として実行しています。
aという変数は a = 0、というメモリ空間に保存されています。
今回引数として関数に渡してあげた場合のaはとりあえずは0です。
関数内で{arg = 1}とした場合は。
```javascript
let arg = a;
arg = 1;
```
と記述した場合と同様になります。
従って、aはレキシカルスコープをたどって「let a = 0;」を参照し、「0」をargは「1」を出力します。

:::note info
引数がプリミティブ値の場合、互いに影響を受けない
:::

### 例2：オブジェクトbが実引数
```javascript
let b = {
    prop:0
}
function f(arg) {
    arg.prop = 1;
    console.log(b,arg); //{prop: 1} {prop: 1}
}
f(b);
```
:::note warn
オブジェクトbの値も変更されます。
:::


この現象を __日本語的__ に段階的に言い直すならば、
1\. 「引数に渡したbというオブジェクトの参照がargにコピーされます。」
2\. 「argというオブジェクはbと同じ __オブジェクトの実体への参照__ を保持しています。」
3\. 「そのため、argの値を変更するとbにも影響が出ます」。


### 例3:分割代入を絡めた場合

オブジェクトを実引数。オブジェクトのプロパティを仮引数に分割代入して値の変化を観察します。
```javascript
let obj = {
    split: 0
}

function f(fugaobj) {//fugaobjにはobjが渡る。
    let { split } = fugaobj; //objのsplitというプロパティを抽出。
    split = 1; //新たな変数splitに1を代入。
    console.log(obj, split) //=> {split: 0} 1
}
f(obj);

//簡単な書き方があるので以下も同じです。1行消せるのとよく使われる書き方です。

function f({split}) { //この段階でsplitのみ抽出できる
    split = 1;
    console.log(obj, split)//=> {split: 0} 1
}
f(obj);

```
:::note info
オブジェクトの中身を抽出して、その値を変更してもオブジェクト自体には影響を及ぼしてないのが確認できました。
:::

さて、次にもう少しオブジェクトの階層が深くなった場合について考えてみます。


```javascript

//split1は参照を持っています(split1:{}の部分)
let obj = {
    split1: {
        split2: 0
    }
}
let { split1 } = obj;//ここもsplit1は参照を持っています

split1.split2 = 1; //参照を持ったsplit1のプロパティを変更すると
console.log(obj, split1); //=> obj: {split1:{split:2 : 1}}

///元のobjも影響を受けることになります。

//一応2段階で分割代入すれば結果は
let obj = {
    split1: {
        split2: 0
    }
}

let { split1 } = obj;
let { split2 } = split1.split2;

split1 = 1
split2 = 2;
console.log(obj, split1, split2);

//objはそのまま、split1 = 1, split2 = 2;
//となります。頭の体操みたいな感じですね。 

```

## まとめ
今回は変数の「参照とコピー」について、自分なりにまとめてみました。
これは一番シンプルな例だと思いますが、 __自分自身__ 日本語がこんがらがります。

次回はもう少し複雑な参照に関する課題について問題を通して学びたいと思います。
間違っている箇所をご指摘いただけると喜びます(笑)

ありがとうございました:relaxed:

## 参考
[【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/learn/lecture/19860904#overview)