
2025 / 02 / 04
오늘은 수업 시간에 Call By Reference와 Call By Value에 대해 배웠습니다.
값에 의한 전달은 정확히 이해를 하고 있었는데 이상하게 참조에 의한 전달은 값을 변경하게 되면 두 변수가 모두 값이 변한다는 것을 까먹어서 항상 헷갈리는 것 같습니다.
이번 포스팅에서는 스프레드 오퍼레이터(Spread Operator)와 함께 값에 의한 전달과 참조에 의한 전달을 예시와 함께 다뤄보겠습니다.
값에 의한 전달
- 변수를 다른 변수에 할당할 때 그 값이 복사되어 전달되는 방식입니다.
- 두 변수는 서로 독립적으로 값을 가지게 되며, 하나의 변수 값을 변경해도 다른 변수에는 영향을 미치지 않습니다.
- score와 copy는 각각 80이라는 값을 가집니다.
- score의 값을 100으로 변경하더라도 copy는 변하지 않고 여전히 80입니다.
- score의 값이 copy에 복사되었기 때문입니다.
let score = 80;
let copy = score;
console.log(score); // 80
console.log(copy); // 80
score = 100;
copy = score;
console.log(score); // 100
console.log(copy); // 80
- 원시값(숫자, 문자열, 불리언 등)을 다룰 때, 값이 복사되어 새로운 변수에 전달됩니다.
- 한 변수의 값이 변경되어도 다른 변수의 값에는 영향을 미치지 않습니다.
참조에 의한 전달
- 배열이나 객체와 같은 참조형 데이터가 변수에 할당될 때 발생합니다.
- 참조형 데이터는 실제 값이 아닌 데이터가 저장된 위치(참조)를 변수에 할당합니다.
- 두 변수가 동일한 객체나 배열을 참조하면, 하나의 변수에서 값을 변경하면 다른 변수의 값도 함께 변경됩니다.
- idol과 idol2는 동일한 객체를 참조합니다.
- idol2.name을 변경하면, idol의 값도 변경됩니다.
- 두 변수가 동일한 객체를 참조하고 있기 때문입니다.
let idol = {
name: "Boynextdoor",
};
let idol2 = idol;
console.log(idol); // { name: 'Boynextdoor' }
console.log(idol2); // { name: 'Boynextdoor' }
idol2.name = "보이넥스트도어";
console.log(idol); // { name: '보이넥스트도어' }
console.log(idol2); // { name: '보이넥스트도어' }
- person1과 person2는 속성 값은 동일하지만, 서로 다른 객체입니다.
- person1 === person2는 false가 됩니다.
- 객체 내의 name 값이 동일하므로 person1.name === person2.name는 true입니다.
let person1 = {
name: "Lee",
};
let person2 = {
name: "Lee",
};
console.log(person1 === person2); // false
console.log(person1.name === person2.name); // true
- 객체나 배열은 값을 복사하는 것이 아니라 참조를 복사합니다.
- 하나의 변수에서 값이 변경되면, 이를 참조하는 다른 변수도 영향을 받습니다.
Spread Operator
- 스프레드 오퍼레이터는 객체나 배열을 복사하거나 새로운 객체를 만들 때 사용합니다.
- 기존의 객체나 배열을 복사하여 새로운 변수로 전달할 수 있습니다.
- 참조형 데이터는 얕은 복사(shallow copy)가 이루어지기 때문에, 중첩된 객체나 배열의 경우 내부 값은 여전히 참조합니다.
- person3는 idol 객체를 복사한 새로운 객체입니다.
- idol의 name은 "Boynextdoor"로 유지되고, person3의 name만 "이한"으로 변경됩니다.
- 두 객체는 독립적인 객체가 되어 서로 영향을 미치지 않습니다.
let person3 = {
...idol,
};
person3.name = "이한";
console.log(idol.name); // Boynextdoor
console.log(person3.name); // 이한
- 스프레드 오퍼레이터를 사용해 idol 객체와 idol4 객체를 합쳤습니다.
- idol4 객체는 idol 객체의 모든 속성을 가지면서, year라는 새로운 속성도 추가되었습니다.
let idol4 = {
year: 2004,
...idol,
};
console.log(idol4); // { year: 2004, name: 'Boynextdoor' }
- numbers2에 numbers 배열을 할당했기 때문에, 동일한 참조를 공유하고 있습니다.
- 하나의 배열에 값을 추가하면, 다른 배열도 영향을 받습니다.
const numbers = [1, 2, 3];
const numbers2 = numbers;
numbers2.push(4);
console.log(numbers); // [ 1, 2, 3, 4 ]
console.log(numbers2); // [ 1, 2, 3, 4 ]
- numbers3는 numbers 배열을 복사하고, 5, 6, 7을 추가한 새로운 배열입니다.
- numbers에 5를 추가해도 numbers3는 영향을 받지 않습니다.
- numbers3가 새로 복사된 배열이기 때문입니다.
const numbers3 = [...numbers, 5, 6, 7];
numbers.push(5);
console.log(numbers); // [ 1, 2, 3, 4, 5 ]
console.log(numbers2); // [ 1, 2, 3, 4, 5 ]
console.log(numbers3); // [ 1, 2, 3, 4, 5, 6, 7 ]
- 스프레드 오퍼레이터 ...를 사용하면 객체나 배열을 복사하거나 합칠 수 있습니다.
- 객체나 배열을 복사할 때 얕은 복사가 이루어져서, 내부의 참조형 값은 여전히 동일한 객체나 배열을 참조합니다.
쇼핑 카트 만들기
- 객체를 사용하여 상품 정보를 저장합니다.
- 배열을 사용하여 여러 상품을 관리할 수 있습니다.
- 객체의 속성을 활용하여 총 금액 계산합니다.
- 상품 추가하고 삭제도 할 수 있습니다.
- 쇼핑 카트의 내용을 콘솔에 출력합니다.
객체를 사용하여 상품 정보를 저장합니다.
- newProduct라는 객체에는 name / price / count의 값이 담겨있습니다.
let newProduct = { name, price, count, };
배열을 사용하여 여러 상품을 관리할 수 있습니다.
- 상품 목록을 담아줄 cart라는 빈 배열을 생성합니다.
- newProduct에 담기는 값을 cart라는 배열에 push하여 넣습니다.
let cart = []; let newProduct = { name, price, count, }; cart.push(newProduct);
객체의 속성을 활용하여 총 금액 계산합니다.
- 총 금액을 계산해주는 getTotalPrice라는 함수를 생섭합니다.
- 총 계산의 값을 담을 totalPrice라는 변수를 선언하고 0으로 초기화합니다.
- for문을 활용하여 카트에 담긴 객체의 price와 count를 가져와 총 금액을 계산합니다.
- 계산된 값이 담긴 totalPrice을 return해줍니다.
function getTotalPrice() { let totalPrice = 0; // 카트에 담긴 모든 상품의 가격과 수량을 곱해서 더함 for (let i = 0; i < cart.length; i++) { totalPrice += cart[i].price * cart[i].count; } return totalPrice; }
상품 추가하고 삭제도 할 수 있습니다.
- 상품을 추가하는 addProduct와 삭제하는 removeProduct라는 함수를 생성합니다.
- addProduct는 매개변수로 name, price, count의 값을 받아옵니다.
- removeProduct는 매개변수로 name, count의 값을 받습니다.
- 삭제되는 함수에는 삼품의 count가 0일 경우 해당 삼품을 삭제할 수 있도록 합니다.
function addProduct(name, price, count) { let newProduct = { name, price, count, }; cart.push(newProduct); } function removeProduct(name, count) { for (let i = 0; i < cart.length; i++) { if (cart[i].name === name) { cart[i].count -= count; // 수량이 0 이하라면 해당 상품 삭제 if (cart[i].count <= 0) { cart.splice(i, 1); } break; // 해당 상품을 찾으면 반복 종료 } } }
쇼핑 카트의 내용을 콘솔에 출력합니다.
- 임의의 값을 넣어 결과를 콘솔에 출력하고 확인합니다.
// 상품 추가 예시 addProduct("앨범1", 20000, 2); // { name: '앨범1', price: 20000, count: 2 } console.log(cart); // [{ name: '앨범1', price: 20000, count: 2 }] // 상품 수량 감소 예시 removeProduct("앨범1", 1); // 앨범1의 수량을 1개 감소 console.log(cart); // [{ name: '앨범1', price: 20000, count: 1 }] console.log(cart); // 전체 가격 출력 console.log("전체 가격은 " + getTotalPrice() + "원 입니다.");
- 위의 코드를 하나로 합쳐놓은 것입니다.
let cart = [];
function addProduct(name, price, count) {
let newProduct = {
name,
price,
count,
};
cart.push(newProduct);
}
function removeProduct(name, count) {
for (let i = 0; i < cart.length; i++) {
if (cart[i].name === name) {
cart[i].count -= count;
// 수량이 0 이하라면 해당 상품 삭제
if (cart[i].count <= 0) {
cart.splice(i, 1);
}
break; // 해당 상품을 찾으면 반복 종료
}
}
}
function getTotalPrice() {
let totalPrice = 0;
// 카트에 담긴 모든 상품의 가격과 수량을 곱해서 더함
for (let i = 0; i < cart.length; i++) {
totalPrice += cart[i].price * cart[i].count;
}
return totalPrice;
}
// 상품 추가 예시
addProduct("앨범1", 20000, 2); // { name: '앨범1', price: 20000, count: 2 }
console.log(cart); // [{ name: '앨범1', price: 20000, count: 2 }]
// 상품 수량 감소 예시
removeProduct("앨범1", 1); // 앨범1의 수량을 1개 감소
console.log(cart); // [{ name: '앨범1', price: 20000, count: 1 }]
console.log(cart);
// 전체 가격 출력
console.log("전체 가격은 " + getTotalPrice() + "원 입니다.");
20일차(2) 후기
- 항상 html파일로 script 파일을 작성해서 그런지 결과값을 console로 출력되게 하려고 하다보니 이게 맞나 싶기도 하고 어려운 점이 있어서 시간이 좀 걸린 것 같습니다.
- 실습 문제도 함께 풀면서 공부 하니까 처음보다는 함수와 객체를 원하는대로 사용할 수 있게된 것 같고 매개변수에 대한 이해도 어느정도 된 것 같습니다.
- 다른 점은 다 괜찮아졌지만 여전히 "변수에 숫자의 합과 같은 값을 담을 때는 초기 값을 0으로 초기화해야 한다"는 것을 계속 까먹어서 큰일입니다. ㅠㅜ
- 객체를 처음 배운 날에는 어려워서 걱정이었는데 문제도 풀고 매일 벨로그에 복습할 겸 정리하다보니까 생각보다 금방 적응하고 어려움이 줄어든 것 같습니다. ʕ •̀ ω •́ ʔ