JavaScript

レシピ

データについて

変数の値渡しと参照渡し

変数から別の変数に代入するときに「値渡し」になるパターンと「参照渡し」になるパターンの違いについて解説します。

この記事のポイント

  • プリミティブ値は「値渡し」になる
  • オブジェクトは「参照渡し」になる
  • オブジェクトを値渡ししたいときは新しいオブジェクトを代入して参照を解除する

目次

変数から変数へ値を代入したときについて

変数から変数に値を代入したとき、値の複製だけが行われる「値渡し」と、値への参照そのものを代入する「参照渡し」の2種類あります。

JavaScriptには文字列(string)、数値(number)、真偽値(boolean)、nullundefinedの5種類の型に分類できる「プリミティブ値」が用意されています。
プリミティブ値が入った変数であれば、別の変数に値を代入したときは「値渡し」になり、2つの変数は独立した変数として扱うことができます。

以下の例はプリミティブ値をもった変数aから変数bに代入を行い、その後に変数aに新しい値を代入して2つの変数の値が個別の値を持っているかconsole.logメソッドで出力して確認します。

コード例

// 数値
var a = 1;
var b = a;
a = 2;

console.log(a); // 2
console.log(b); // 1


// 文字列
var a = 'テスト';
var b = a;
a = '文字を変更';

console.log(a); // '文字を変更'
console.log(b); // 'テスト'


// 真偽値
var a = true;
var b = a;
a = false;

console.log(a); // false
console.log(b); // true


// null
var a = null;
var b = a;
a = 1;

console.log(a); // 1
console.log(b); // null


// undefined
var a = undefined;
var b = a;
a = 1;

console.log(a); // 1
console.log(b); // undefined

それぞれの型の値を持つ変数aに対して、変数bに代入してから新しい値を代入してみると、変数aと変数bは別々の値を持っていることが確認できました。
このことから、プリミティブ値は「値渡し」が行われていることが確認できます。
つまり、変数aから変数bに代入した後は、それぞれの変数で値を更新してもお互いに干渉しません。

変数の参照渡しと参照解除

プリミティブ値は「値渡し」となりましたが、変数に入っている値が配列やオブジェクトの場合は参照渡しになります。
以下の例は変数aに入っている配列を変数bに代入し、その後に変数aに入っている配列の値を更新してからconsole.logメソッドで出力します。

コード例

var a = ['lion','cat','dog'];
var b = a;

a[0] = 'rhinos';
a[2] = 'squirrel';

console.log(a);
// (3) ["rhinos", "cat", "squirrel"]

console.log(b);
// (3) ["rhinos", "cat", "squirrel"]

変数aの配列の値しか更新していないつもりが、変数bの配列についても更新されていることが分かります。

これは変数aから変数bに代入されたものは配列そのものではなく、配列への参照情報を渡していることが原因です。
参照情報だけを渡しているので、変数aと変数bは全く同じ配列を参照していることになります。

そのため、変数bから配列の値を更新した場合についても同様に変数aの配列も更新されます。

コード例

var a = ['lion','cat','dog'];
var b = a;

// 変数aから配列を更新
a[0] = 'rhinos';
a[2] = 'squirrel';

console.log(a);
// (3) ["rhinos", "cat", "squirrel"]

console.log(b);
// (3) ["rhinos", "cat", "squirrel"]

// 変数bから配列を更新
b[0] = 'red';
b[1] = 'blue';
b[2] = 'black';

console.log(a);
// (3) ["red", "blue", "black"]

console.log(b);
// (3) ["red", "blue", "black"]

このような参照情報を代入することを「参照渡し」と呼びます。
先述したプリミティブ値以外の値(オブジェクト)に持つ変数は参照渡しになります。

以下の例はオブジェクトを値に持つ変数aから変数bに代入を行い、プロパティの値を更新してconsole.logメソッドで値を確認します。

コード例

var a = {
  id:15001,
  name:'emilia'
};
var b = a;
a.id = 15005;

console.log(a);
// {id: 15005, name: "emilia"}

console.log(b);
// {id: 15005, name: "emilia"}

b.name = 'emily';

console.log(a);
// {id: 15005, name: "emily"}

console.log(b);
// {id: 15005, name: "emily"}

変数aと変数bは同じオブジェクトを参照しているため、どちらの変数からもプロパティの値を更新できることが分かります。
それぞれの変数のオブジェクトを個別に扱いたい場合は、以下のように変数aに新しいオブジェクトを入れることで以前のオブジェクトへの参照を解除します。

コード例

var a = {
  id:15001,
  name:'emilia'
};
var b = a;

console.log(a);
// {id: 15003, name: "emilia"}

console.log(b);
// {id: 15001, name: "emilia"}


var a = {
  id:15003,
  name:'emilia'
};

b.id = 15222;
b.name = 'emily';

console.log(a);
// {id: 15003, name: "emilia"}

console.log(b);
// {id: 15222, name: "emily"}

変数bに代入した後に、変数aのオブジェクトを改めて代入しているところがポイントです。
このように新しいオブジェクトを入れることで変数aの参照を切り替えることができ、それぞれの変数に入っているオブジェクトを個別に扱うことができます。

こちらの記事は役に立ちましたか?

ありがとうございます。
もしよろしければ、あわせてフィードバックや要望などをご入力ください。

コメントありがとうございます!
運営の参考にさせていただきます。