概要
JavaScript では、関数に引数を渡す際の挙動が「プリミティブ型」と「オブジェクト型(配列を含む)」で異なります。
本記事では具体例を挙げながら解説します。
プリミティブ型
数値や文字列、真偽値などのプリミティブ型は、関数内で再代入しても、呼び出し元の変数には影響しません。
function inc(x) {
x = x + 1;
console.log("関数内:", x); // 関数内: 2
}
let a = 1;
inc(a);
console.log("呼び出し元 a:", a); // 呼び出し元 a: 1
オブジェクト型(配列含む)は「参照のコピー」が渡される
- 関数内でプロパティ/要素を変更すると、呼び出し元のオブジェクト/配列にも影響が及ぶ
- 関数内で引数変数を別のオブジェクト/配列に再代入しても、呼び出し元の参照は変わらない
オブジェクトの場合
function setName(o) {
o.name = "太郎"; // (A) 呼び出し元 person.name が "太郎" に
o = { name: "次郎" }; // (B) o を新しいオブジェクトに再代入
console.log("関数内 o:", o.name); // 関数内 o: 次郎
}
let person = { name: "一郎" };
setName(person);
console.log("呼び出し元 person:", person.name); // 呼び出し元 person: 太郎
- (A) では、
o.name = "太郎"
によって呼び出し元のperson.name
も "太郎" になる - (B) の
o = {…}
は関数内の変数o
に新しい参照を割り当てるだけで、呼び出し元のperson
は変わらない
配列の場合
function modifyArray(arr) {
// (1) 要素の変更は呼び出し元にも反映
arr[0] = "B";
// (2) 変数自体を再代入しても呼び出し元には影響なし
arr = ["X", "Y", "Z"];
console.log("関数内 arr の再代入後:", arr); // ["X","Y","Z"]
}
let original = ["A","A","A"];
modifyArray(original);
console.log("呼び出し元 original:", original); // ["B","A","A"]
- (1) の
arr[0] = "B"
によって、呼び出し元original[0]
も"B"
に - (2) の
arr = […]
はローカル変数の再代入なので、original
には影響しない
スプレッド構文で配列をコピーするときの挙動(浅いコピー)
関数の引数ではないですが、スプレッド構文 [...] を使うと、新しい配列オブジェクトが作成されます。
しかし、その要素として格納されるオブジェクト自体は元の配列と同じ参照となる「浅いコピー(shallow copy)」になります。
たとえば以下の例を見てみましょう。
const original = [{ name: "A" }, { name: "B" }];
const shallowCopy = [...original];
// 配列自体は別インスタンス
console.log(original === shallowCopy); // false
// 要素(オブジェクト)は同じ参照
console.log(original[0] === shallowCopy[0]); // true
// shallowCopy に要素を追加しても original には影響しない
shallowCopy.push({ name: "C" });
console.log(original.length); // 2
console.log(shallowCopy.length); // 3
// しかし要素のプロパティを変更すると original も変わる
shallowCopy[0].name = "Z";
console.log(original[0].name); // "Z"
上記のとおり、shallowCopy 自体は別の配列です。
shallowCopy.push(...) で要素を足しても元配列 original は変わらなりません。
しかし、配列内のオブジェクトを直接操作すると同じオブジェクトを参照しているため、original の中身も変化するという挙動になります。
まとめ
プリミティブ型
再代入しても呼び出し元は変わらない
オブジェクト型/配列
「参照のコピー」が渡され、プロパティや要素の変更は呼び出し元にも反映される。
一方、引数変数自体の再代入は影響しない