JavaScript에서는 데이터를 전달할 때 "passed by value"와 "passed by reference" 두 가지 방식을 사용합니다.
Passed by Value (값에 의한 전달): 원시 데이터 유형(예: 숫자, 문자열, 불린, null, undefined, 심볼)을 다룰 때 사용됩니다. Passed by Value에서는 데이터가 변수로 복사되며, 변수와 복사본은 서로 독립적입니다. 따라서 원본 데이터를 변경해도 복사본은 영향을 받지 않습니다.
let a = 5;
let b = a; // 'a'의 값이 'b'로 복사됨
a = 10;
console.log(b); // 출력 결과는 5
Passed by Reference (참조에 의한 전달): 복합 데이터 유형(객체, 배열, 함수)을 다룰 때 사용됩니다. Passed by Reference에서는 데이터 구조(객체 또는 배열)에 대한 참조(메모리 위치)가 변수에 저장되며, 변수는 데이터를 가리키는 포인터 역할을 합니다. 따라서 변수를 통해 데이터 구조를 변경하면 모든 변수가 영향을 받습니다.
let obj1 = { name: 'Alice' };
let obj2 = obj1; // 'obj1'의 참조가 'obj2'로 복사됨
obj1.name = 'Bob';
console.log(obj2.name); // 출력 결과는 'Bob' (두 변수가 동일한 객체를 가리킴)
이때, 변수 obj1과 obj2는 동일한 객체를 가리키기 때문에 한 변수를 통해 객체를 변경하면 다른 변수에도 변경 내용이 반영됩니다.
JavaScript에서 함수 인수 전달은 "값에 의한 전달"입니다. 함수 내에서 매개변수의 값을 변경하더라도 호출자의 변수는 영향을 받지 않습니다. 그러나 만약 함수의 매개변수로 객체나 배열을 전달하고 함수 내에서 해당 객체나 배열을 변경한다면 이 변경 사항은 호출자에게도 반영됩니다.
Passed by Value (값에 의한 전달)로 생길 수 있는 문제
원시 데이터 유형의 불변성: Passed by Value로 처리되는 원시 데이터 유형(숫자, 문자열, 불린, null, undefined, 심볼)은 불변하다는 특성을 가지고 있습니다. 이는 데이터를 변경할 때 새로운 값을 할당해야 함을 의미합니다. 하지만 이로 인해 메모리 사용량이 늘어날 수 있고, 불필요한 데이터 복사가 발생할 수 있습니다.
Passed by Reference (참조에 의한 전달)로 생길 수 있는 문제
Passed by Reference로 처리되는 객체와 배열은 참조에 의한 전달이기 때문에 여러 변수가 동일한 데이터를 가리킬 수 있습니다. 이는 의도치 않은 데이터 변경으로 이어질 수 있으며 디버깅이 어려울 수 있습니다.
let arr1 = [1, 2, 3];
let arr2 = arr1; // arr1과 arr2가 동일한 배열을 가리킴
// 의도치 않은 데이터 변경
arr1.push(4);
console.log(arr2); // [1, 2, 3, 4]
비동기 작업에서 발생하는 문제: 비동기 작업에서 Passed by Reference의 동작 방식은 예상치 못한 결과를 초래할 수 있습니다. 비동기 작업이 완료되기 전에 변수가 변경되는 경우 문제가 발생할 수 있습니다.
let value = 1;
setTimeout(() => {
value = 2;
}, 1000);
console.log(value); // 1 (비동기 작업이 완료되기 전에 로그가 출력됨)
데이터 누출 및 보안 문제: Passed by Reference의 경우 다른 변수가 데이터에 대한 참조를 공유하므로 데이터 보안 문제가 발생할 수 있습니다. 또한 데이터 누출이 발생할 수 있으므로 개인 정보 보호에 주의해야 합니다.
ES6 이후에는 const와 let 키워드를 사용하여 변수를 선언하는 방식이 개선되어 데이터 변경을 방지하고, 객체나 배열을 변경하지 않고 새로운 객체나 배열을 생성하는 방식을 적극 활용하여 코드를 더 예측 가능하게 만들 수 있습니다.
해결법
객체나 배열을 변경하지 않고 새로운 객체나 배열을 생성하는 방식은 **불변성 (Immutability)**을 유지하고 데이터를 안전하게 다루는 중요한 개념입니다. JavaScript에서 불변성을 유지하려면 다음과 같은 방법을 사용할 수 있습니다
객체 또는 배열 복사 (Object/Array Copying): 원본 객체나 배열을 변경하지 않고 새로운 객체나 배열을 생성합니다. 이것을 통해 원본 데이터는 보존되며 변경된 복사본을 사용할 수 있습니다.
// 배열 복사
const originalArray = [1, 2, 3];
const copiedArray = [...originalArray];
copiedArray.push(4);
console.log(originalArray); // [1, 2, 3]
console.log(copiedArray); // [1, 2, 3, 4]
// 객체 복사
const originalObject = { name: 'Alice', age: 30 };
const copiedObject = { ...originalObject };
copiedObject.age = 31;
console.log(originalObject); // { name: 'Alice', age: 30 }
console.log(copiedObject); // { name: 'Alice', age: 31 }
Array.map() 및 Object.assign(): Array.map() 함수를 사용하여 배열의 각 요소를 변경하거나 Object.assign() 함수를 사용하여 객체에 새로운 속성을 추가할 수 있습니다. 이러한 함수들은 새로운 배열 또는 객체를 반환합니다.
// 배열의 각 요소를 변경
const originalArray = [1, 2, 3];
const newArray = originalArray.map(item => item * 2);
console.log(originalArray); // [1, 2, 3]
console.log(newArray); // [2, 4, 6]
// 객체에 새로운 속성 추가
const originalObject = { name: 'Alice' };
const newObject = Object.assign({}, originalObject, { age: 30 });
console.log(originalObject); // { name: 'Alice' }
console.log(newObject); // { name: 'Alice', age: 30 }
전개 연산자 (Spread Operator): 전개 연산자 (...)를 사용하여 배열이나 객체를 복사하거나 새로운 요소를 추가할 수 있습니다.
// 배열 복사 및 요소 추가
const originalArray = [1, 2, 3];
const copiedArray = [...originalArray, 4];
console.log(originalArray); // [1, 2, 3]
console.log(copiedArray); // [1, 2, 3, 4]
// 객체 복사 및 새로운 속성 추가
const originalObject = { name: 'Alice' };
const newObject = { ...originalObject, age: 30 };
console.log(originalObject); // { name: 'Alice' }
console.log(newObject); // { name: 'Alice', age: 30 }'cs 공부' 카테고리의 다른 글
| NoSQL과 RDBMS의 특징과 차이점에 대해서 장, 단점을 들어 설명해주세요. (0) | 2023.10.19 |
|---|---|
| JWT에 대해 설명해주실 수 있을까요 (0) | 2023.10.16 |
| 깊은 복사와 얕은 복사의 차이는 무엇이고 JS에서 각각을 구현하는 방법은 어떻게 되는지 설명해주실 수 있을까요? (0) | 2023.10.16 |
| 모든 요소에 인덱스를 걸지 않는 이유는 무엇일까요? (0) | 2023.10.16 |
| 사용자 패스워드를 전송하고 보관하는 방법을 설명해주실 수 있을까요? (0) | 2023.10.16 |