JavaScriptにおける変数の渡し方
JavaScriptは、変数の渡し方に大きく分けて2つの方法があります:値渡しと参照渡しです。これは、特にTypeScriptやAngularなどのフレームワークを使用する際に理解しておくと、変数の振る舞いを正確に把握し、予期しない挙動を防ぐのに役立ちます。
値渡し (Pass by Value)
- 影響
関数内でそのコピーを変更しても、元の変数の値には影響しません。 - 仕組み
関数に値が渡されるとき、その値のコピーが作成され、関数内でそのコピーが使用されます。 - 基本的なデータ型
数値、文字列、ブーリアンなどの基本的なデータ型は、値渡しされます。
例
function changeValue(num) {
num = 10;
}
let x = 5;
changeValue(x);
console.log(x); // 出力: 5
参照渡し (Pass by Reference)
- 影響
関数内でオブジェクトや配列を変更すると、元のオブジェクトや配列も変更されます。 - 仕組み
関数にオブジェクトや配列が渡されるとき、そのオブジェクトや配列のメモリ上のアドレスが渡されます。つまり、関数内では元のオブジェクトや配列そのものが操作されることになります。 - オブジェクトと配列
オブジェクトや配列などの複合的なデータ型は、参照渡しされます。
function changeArray(arr) {
arr.push(3);
}
let myArray = [1, 2];
changeArray(myArray);
console.log(myArray); // 出力: [1, 2, 3]
TypeScriptとAngularにおける考慮点
- Angular
Angularでは、コンポーネント間でデータを共有する際に、入力プロパティや出力プロパティを使用します。これらのプロパティは、基本的に値渡しと参照渡しの概念に従います。 - TypeScript
TypeScriptはJavaScriptのスーパーセットであり、型システムを導入することでより厳密なコードを書くことができます。しかし、値渡しと参照渡しの基本的な概念はJavaScriptと同じです。
- 変数の渡し方に関する理解は、特にオブジェクトや配列を扱う際に重要です。
- TypeScriptとAngularでは、JavaScriptのこれらの概念を継承しています。
- JavaScriptでは、基本的なデータ型は値渡し、オブジェクトや配列は参照渡しされます。
注意
- 特に、オブジェクトのプロパティを変更する場合や、オブジェクトを再代入する場合には注意が必要です。
- JavaScriptの参照渡しは、他の言語の参照渡しとは少し異なる挙動を示すことがあります。
function changeValue(num) {
num = 10; // 関数内でnumの値を変更
console.log("関数内でのnum:", num); // 10が出力される
}
let x = 5;
changeValue(x);
console.log("関数呼び出し後のx:", x); // 5が出力される
- 解説
changeValue
関数に渡されたnum
は、x
のコピーです。- 関数内で
num
の値を10に変更しても、元のx
の値は5のままです。
参照渡しは、変数が指すオブジェクトのメモリ上のアドレスが関数に渡される方法です。関数内でオブジェクトを変更すると、元のオブジェクトも変更されます。
function changeArray(arr) {
arr.push(3); // 配列に要素を追加
}
let myArray = [1, 2];
changeArray(myArray);
console.log(myArray); // [1, 2, 3]が出力される
- 解説
changeArray
関数に渡されたarr
は、myArray
を指す参照です。- 関数内で
arr
に要素を追加すると、myArray
自体も変更されます。
オブジェクトのプロパティの変更
function changeObject(obj) {
obj.name = "太郎";
}
let person = { name: "次郎" };
changeObject(person);
console.log(person.name); // 太郎が出力される
- 解説
changeObject
関数に渡されたobj
は、person
オブジェクトへの参照です。- 関数内で
obj.name
を変更すると、person.name
も変更されます。
データ型 | 渡されるもの | 関数内での変更が元の変数に影響するか |
---|---|---|
数値、文字列、ブーリアン | 値のコピー | 影響しない |
オブジェクト、配列 | 参照 | 影響する |
- TypeScript
TypeScriptは静的型付け言語なので、変数の型を明示的に指定することで、値渡しと参照渡しの違いをより明確に把握できます。
重要なポイント
- 特に、オブジェクトを再代入する場合には注意が必要です。
これらのコード例と解説を通して、JavaScriptにおける値渡しと参照渡しの概念をより深く理解できるはずです。
さらに詳しく知りたい場合は、以下のキーワードで検索してみてください。
- Angular 値渡し 参照渡し
- TypeScript 値渡し 参照渡し
スプレッド構文 (Spread Syntax) を用いた浅いコピー
- 注意点
オブジェクト内にネストされたオブジェクトは、参照渡しとなります。 - 方法
スプレッド構文 (...) を使用して、新しいオブジェクトや配列を作成します。 - 目的
オブジェクトや配列の浅いコピーを作成し、値渡しのように振る舞わせたい場合。
let originalArray = [1, 2, 3];
let copyArray = [...originalArray];
copyArray.push(4);
console.log(originalArray); // [1, 2, 3]
console.log(copyArray); // [1, 2, 3, 4]
Object.assign() を用いた浅いコピー
- 方法
Object.assign()
メソッドを使用して、既存のオブジェクトのプロパティを新しいオブジェクトにコピーします。 - 目的
オブジェクトの浅いコピーを作成する場合。
let originalObject = { a: 1, b: 2 };
let copyObject = Object.assign({}, originalObject);
copyObject.a = 10;
console.log(originalObject); // { a: 1, b: 2 }
console.log(copyObject); // { a: 10, b: 2 }
JSON.stringify() と JSON.parse() を用いた深コピー
- 注意点
循環参照や関数など、すべてのオブジェクトが JSON 化できるわけではありません。 - 方法
オブジェクトを JSON 文字列に変換し、再度パースすることで、新しいオブジェクトを作成します。 - 目的
オブジェクトや配列の深コピーを作成し、完全に独立したコピーを作成したい場合。
let originalObject = { a: 1, b: { c: 3 } };
let copyObject = JSON.parse(JSON.stringify(originalObject));
copyObject.b.c = 10;
console.log(originalObject); // { a: 1, b: { c: 3 } }
console.log(copyObject); // { a: 1, b: { c: 10 } }
Lodash などのライブラリを利用する
- メリット
多くのユーティリティ関数が提供されており、オブジェクトの操作が容易になります。 - 方法
Lodash のcloneDeep
などの関数を使用することで、深コピーを簡単に作成できます。 - 目的
より複雑なオブジェクトの複製や操作を行う場合。
const _ = require('lodash');
let originalObject = { a: 1, b: { c: 3 } };
let copyObject = _.cloneDeep(originalObject);
カスタム関数を作成する
- 方法
再帰関数などを使用して、オブジェクトを深く探索し、新しいオブジェクトを作成します。 - 目的
特定のオブジェクト構造に対して、カスタマイズされたコピー関数を作成する場合。
JavaScriptにおける値渡しと参照渡しの代替方法は、状況に応じて使い分けることが重要です。
- 深コピー
JSON.stringify() と JSON.parse()、Lodash などのライブラリ、カスタム関数を使用。 - 浅いコピー
スプレッド構文やObject.assign()
を使用。
選択のポイント
- パフォーマンス
大量のデータをコピーする場合は、パフォーマンスを考慮する必要があります。 - オブジェクトの構造
複雑な構造の場合は、Lodash などのライブラリが便利です。 - コピーの深さ
浅いコピーで十分か、深いコピーが必要か。
- 循環参照がある場合は、深コピーがうまくいかないことがあります。
- 深コピーはオーバーヘッドが大きい場合があります。
typescript angular