概要
タイトルの答えはYES.
JSを勉強し始めたばかりで、JSにおける値渡し/参照渡し/参照の値渡しの処理の違いがわかりませんでした。
調べていくうちに「え、JSって参照渡ししないんだ!?」となったので、ここに学んだことをまとめようと思います。
追記:いただいたコメントをもとに修正しました。コメントありがとうございます!
結論
- JSでの処理は「プリミティブ値は値渡し」「オブジェクトは参照渡し」と言われていますが、厳密には「参照渡し」はしません。
- JSでは「参照の値渡し」(共有渡し、本文中では共有渡しに統一)が行われています。
値渡し、参照渡し、共有渡しとは
- 値渡し
- 引数に値を渡す時、変数の値をコピーして渡す処理。
- 呼び出しもとの変数は変化しません。
- 引数に値を渡す時、変数の値をコピーして渡す処理。
- 参照渡し
- 引数に値を渡す時、参照(=メモリ番地)で渡す処理。
- 変更が呼び出しもとに反映されます。
- 引数に値を渡す時、参照(=メモリ番地)で渡す処理。
- 共有渡し
- 引数に値を渡す時、変数に格納されている参照をコピーして渡す処理。
- 大抵の言語はオブジェクトを渡す時にこの形態になります。
- 参照渡しと似ているように感じますが、実際には違う動きをします。
- 引数に値を渡す時、変数に格納されている参照をコピーして渡す処理。
JSにおける処理
言葉の意味だけではわかりづらいので、実際に挙動の確認をしてみましょう。
わかりやすいように「プリミティブ値は値渡し」「オブジェクトは参照渡し」と呼ばれているものの処理を比較します。
JSの基本的な処理
値が生成されると、変数aにその参照が割り当てられます。
- 変数aに値10が渡された時の参照をS1とします。
- 全てのサンプルコードにおいて、定義後の参照をS1、再代入後の参照をS2と表記しています。
- サンプルコードは参考記事(下記掲載)の引用です。
- b = aを定義するとbにはS1が割り当てられます。
- イメージ的には b → S1 → 10のようなたどり方をします。
var a = 10 // S1
var b = a // bにS1が渡される
console.log(b) // 10
「プリミティブ値は値渡し」と呼ばれているものの処理
var a = 10
var b = a
a = 100
console.log(b) // 10
//解説
var a = 10 // S1
var b = a // bにS1が渡される
a = 100 // 再代入したのでa = 100にS2が割り当てられる
console.log(b) // bにはS1が渡されているのでS1 = 10が成立
「オブジェクトは参照渡し」と呼ばれているものの処理
b = { val: 100 }が成立したことで参照渡しをしているように見えますが、実際は違います。
仮にJSが参照渡しであった場合、S1がS2に変更になります。
var a = { val: 10 }
var b = a
a.val = 100
console.log(b) // { val: 100 }
//解説
var a = { val: 10 } // S1
var b = a // bにS1が渡される
a.val = 100
// value値が100に変更
// 同じオブジェクトを操作しているため、aの参照がS2に変更されたわけではない
// bにはそのままS1が渡される
console.log(b) // { val: 100 }
// 参照渡しではない
おわりに
もし誤りがあれば指摘いただけるとありがたいです。