반복문은 같은 코드를 여러 번 실행할 때 사용하는 기능이에요. 매번 똑같은 코드를 복사-붙여넣기 하는 대신, 반복문으로 간단하게 처리할 수 있어요.
break는 반복문을 완전히 중단하고 빠져나올 때 사용해요.
for (let i = 0; i < 10; i++) {
if (i === 5) {
break; // i가 5가 되면 반복문 종료
}
console.log(i); // 0, 1, 2, 3, 4만 출력
}
continue는 현재 반복만 건너뛰고 다음 반복으로 넘어갈 때 사용해요.
for (let i = 0; i < 5; i++) {
if (i === 2) {
continue; // i가 2일 때만 건너뜀
}
console.log(i); // 0, 1, 3, 4 출력 (2는 건너뜀)
}
함수는 특정 작업을 수행하는 코드 묶음이에요. 한 번 만들어두면 필요할 때마다 불러서 사용할 수 있어요. 마치 레시피처럼, 한 번 작성해두면 언제든 그 레시피대로 요리할 수 있는 거죠.
// 함수 선언
function greet(name) {
return `안녕하세요, ${name}님!`;
}
// 함수 호출
console.log(greet('아엔')); // "안녕하세요, 아엔님!"
함수를 사용하는 이유:
코드 재사용: 같은 코드를 여러 번 쓰지 않아도 돼요
유지보수: 수정할 때 한 곳만 고치면 돼요
가독성: 코드가 깔끔하고 이해하기 쉬워져요
배열의 고급 메서드들을 알아볼게요. 이 메서드들은 배열을 효율적으로 다룰 수 있게 해줘요.
indexOf: 특정 값의 인덱스 찾기
let fruits = ['사과', '바나나', '오렌지'];
console.log(fruits.indexOf('바나나')); // 1
console.log(fruits.indexOf('포도')); // -1 (없으면 -1 반환)
includes: 특정 값이 있는지 확인
console.log(fruits.includes('사과')); // true
console.log(fruits.includes('포도')); // false
slice: 배열의 일부를 복사
let numbers = [1, 2, 3, 4, 5];
let sliced = numbers.slice(1, 4); // [2, 3, 4]
// 원본 배열은 변하지 않음
splice: 배열의 요소를 추가/제거
let numbers = [1, 2, 3, 4, 5];
numbers.splice(2, 1); // 인덱스 2부터 1개 제거 -> [1, 2, 4, 5]
numbers.splice(2, 0, 3); // 인덱스 2에 3 추가 -> [1, 2, 3, 4, 5]
JavaScript에서 포인터는 C언어처럼 명시적으로 존재하지는 않지만, 참조(Reference) 개념으로 이해할 수 있어요.
원시 타입(Primitive): 값 자체가 복사돼요
let a = 10;
let b = a; // 값이 복사됨
b = 20;
console.log(a); // 10 (변하지 않음)
console.log(b); // 20
참조 타입(Reference): 주소가 복사돼요
let arr1 = [1, 2, 3];
let arr2 = arr1; // 주소가 복사됨 (같은 배열을 가리킴)
arr2.push(4);
console.log(arr1); // [1, 2, 3, 4] (arr1도 변함!)
console.log(arr2); // [1, 2, 3, 4]
이렇게 객체나 배열은 실제 값이 아니라 메모리 주소를 저장하기 때문에, 한쪽을 수정하면 다른 쪽도 영향을 받아요. 이를 방지하려면 복사본을 만들어야 해요.
let arr1 = [1, 2, 3];
let arr2 = [...arr1]; // 스프레드 연산자로 새 배열 생성
arr2.push(4);
console.log(arr1); // [1, 2, 3] (변하지 않음)
console.log(arr2); // [1, 2, 3, 4]
배열도 참조 타입이기 때문에 포인터처럼 동작해요. 배열을 다룰 때는 이 점을 항상 주의해야 해요.
// 잘못된 복사 (얕은 복사)
let original = [1, 2, 3];
let copy = original;
copy[0] = 100;
console.log(original); // [100, 2, 3] - 원본도 변함!
// 올바른 복사 방법 1: 스프레드 연산자
let original2 = [1, 2, 3];
let copy2 = [...original2];
copy2[0] = 100;
console.log(original2); // [1, 2, 3] - 원본은 안 변함
// 올바른 복사 방법 2: slice()
let copy3 = original2.slice();
// 올바른 복사 방법 3: Array.from()
let copy4 = Array.from(original2);
중첩 배열의 경우 :
let nested = [[1, 2], [3, 4]];
let shallowCopy = [...nested];
shallowCopy[0][0] = 100;
console.log(nested); // [[100, 2], [3, 4]] - 내부 배열은 여전히 공유됨!
// 깊은 복사가 필요할 때
let deepCopy = JSON.parse(JSON.stringify(nested));
함수에 배열이나 객체를 전달할 때도 참조가 전달되기 때문에, 함수 내부에서 수정하면 원본도 변경돼요.
참조로 전달되는 경우:
function modifyArray(arr) {
arr.push(4);
arr[0] = 100;
}
let myArray = [1, 2, 3];
modifyArray(myArray);
console.log(myArray); // [100, 2, 3, 4] - 원본이 변경됨!
원본을 보호하려면:
function modifyArray(arr) {
let newArr = [...arr]; // 복사본 생성
newArr.push(4);
newArr[0] = 100;
return newArr;
}
let myArray = [1, 2, 3];
let result = modifyArray(myArray);
console.log(myArray); // [1, 2, 3] - 원본은 안전!
console.log(result); // [100, 2, 3, 4] - 새로운 배열
함수의 매개변수:
function changeValue(num, arr) {
num = 100; // 원본에 영향 없음
arr[0] = 100; // 원본이 변경됨!
}
let number = 10;
let array = [1, 2, 3];
changeValue(number, array);
console.log(number); // 10 (변하지 않음)
console.log(array); // [100, 2, 3] (변경됨)