모딥다 8장 제어문을 읽었다. 실무에서 잘 사용 안하게 되는 레이블 문과 break, continue 부분은 생소하다고 느끼는 부분도 있었고, for문이나 while 문도 오랜만에 봤다. 크게 더 파볼만한(?) 부분은 안 보여서 책에서 언급만 하고 다루지 않은 문법들 위주로 좀 더 살펴보았다.

1. for...in과 for...of
for...in
const person = { name: '유진', gender: 'female', job: '개발자' };
for (const key in person) {
console.log(key, person[key]);
}
// name 유진
// gender female
// job 개발자
for...in은 객체의 키(key)를 순회한다.
for...of
const fruits = ['사과', '바나나', '포도'];
for (const fruit of fruits) {
console.log(fruit);
}
// 사과
// 바나나
// 포도
for...of는 배열 같은 이터러블의 값(value)을 순회한다.
주의할 점은 배열에도 for...in를 사용할 수는 있지만, 이 경우 인덱스가 나온다는 것이다. (그리고 타입은 문자열.. 왤까?)
const arr = ['a', 'b', 'c'];
for (const i in arr) {
console.log(i, typeof i); // "0" string, "1" string, "2" string
}
의도치 않은 버그의 원인이 될 수 있으니, 배열 순회에는 for...of를 쓰자.
2. Object.keys / values / entries
for...in을 잘 몰랐던 이유는.. 그동안은 보통 객체를 순회할때 Object.keys/values/entries 를 주로 써왔기 때문일 것이다.
const person = { name: '유진', age: 25, job: '개발자' };
Object.keys(person) // ['name', 'age', 'job']
Object.values(person) // ['유진', 25, '개발자']
Object.entries(person) // [['name','유진'], ['age',25], ['job','개발자']]
특히 셋 다 배열을 반환하기 때문에 map, filter 같은 배열 메서드를 바로 쓸 수 있다.
// 키만 필요할 때
Object.keys(person).includes('name') // true
// 값만 필요할 때
Object.values(person).some(v => typeof v === 'number') // true
// 키+값 둘 다 필요할 때
Object.entries(person).forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
Object.entries()를 알면 대부분의 객체 순회 상황에서 충분하다. 상황에 따라 for ... in 도 활용해봐야겠다.
3. const인데 왜 값이 바뀌어? — 반복문의 스코프
for...in 코드를 보다가 한 가지 의문이 생겼다.
for (const key in person) { ... }
const는 재할당이 안 되는 거 아니었나? 그런데 매 반복마다 key에 다른 값이 들어간다. 왜 const 를 쓰는걸까?
결론은 매 반복이 새로운 스코프라서 같은 변수에 재할당하는 게 아니라, 매번 새로운 const 변수가 만들어지는 것이다.
1회차: const key = 'name' ← 새 스코프
2회차: const key = 'age' ← 새 스코프
3회차: const key = 'job' ← 새 스코프
let으로 써도 동작하지만, 블록 안에서 실수로 값을 덮어쓸 위험이 있다. 오히려 const를 쓰는 것이 더 안전한 것이다.
for (let key in person) {
key = 'oops'; // 에러 없이 덮어써버림
console.log(key); // 'oops' 'oops' 'oops'
}
4. in 연산자
for...in의 in도 단독으로 쓸 수 있는 키워드였다.
const person = { name: '유진', age: 25 };
'name' in person // true
'job' in person // false
먼저 in 이 객체와 쓰일 때는 "이 키가 객체에 있는가?"를 true/false로 알려준다.
배열에서도 동작하는데, 확인하는 건 값이 아니라 인덱스(키)다.
const arr = ['a', 'b', 'c'];
0 in arr // true (인덱스 0 존재)
1 in arr // true (인덱스 1 존재)
2 in arr // true (인덱스 2 존재)
3 in arr // false (인덱스는 2까지만 존재하니까)
'a' in arr // false (값이 아니라 키를 확인!)
5. 프로토타입 체인
위에서 다룬 것처럼 in은 객체에 키가 존재하는지를 확인하기 위해 사용될 수 있다.
const obj = { a: 1 };
'a' in obj // true
'toString' in obj // true - ?_?
그런데 in을 쓰면 위와 가이 만든 적이 없는 키도 toString 존재한다고 한다. 이는 프로토타입 체인 때문이다
JavaScript의 모든 객체는 부모 객체(프로토타입)를 가지고 있고, 거기서 속성을 물려받는다.
const parent = { greet: '안녕' };
const child = Object.create(parent);
child.name = '유진';
child → parent
{ name: '유진' } { greet: '안녕' }
(자신의 속성) (물려받은 속성)
in 연산자는 이 체인을 타고 올라가면서 속성을 찾는다.
'name' in child // true — 자기 것
'greet' in child // true — 부모 것도 true!
그래서 'toString' in obj는 true이다. (모든 객체는 Object.prototype에서 toString을 물려받기 때문에)
자기 자신의 속성만 정확히 확인하려면 Object.hasOwn()을 쓴다.
Object.hasOwn(child, 'name') // true — 자기 것
Object.hasOwn(child, 'greet') // false — 부모 것은 false
in 이 더 간단하게 사용할 수 있을 것 같지만 예측 가능성을 높이려면 Object.hasOwn 을 쓰는 것이 더 안정적일 것 같다.
마지막으로 하나만 더,,, for...in을 배열에 대해 사용할 때 왜 키 값이 문자열 인덱스 값이 나올까?
이는 JavaScript에서 배열은 특별한 문법이 아니라 객체이기 때문이다. 배열은 js에서 내부적으로 이렇게 저장된다
const arr = ['a', 'b', 'c'];
// 실제 내부 구조 (개념적)
{
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
}
결국 배열의 각 요소는 문자열 인덱스를 키로 가지는 프로퍼티인 것이다. for...in은 프로퍼티 키를 순회하므로, 배열에 사용하면 '0', '1', '2' 같은 인덱스(문자열)가 나오게 되는 것이다.
다만 배열에 for...in 사용은 권장하지 않는다고 한다. 그 이유중 하나는 '순서가 보장되지 않는다'는 건데 ES2015+ 스펙에서는 for...in 에 사용하는 연산에 대해 아래와 같이 명시하고 있다고 한다.
"The mechanics and order of enumerating the properties is not specified"
(프로퍼티 열거의 메커니즘과 순서는 명시하지 않는다)
실제로 브라우저들은 대부분은 순서대로 나오게 구현을 해두긴해서 많은 경우 순서대로 나오긴 하지만, 어쨌든 스펙 상으로는 순서 보장이 안되는 것이기 때문에 '순회' 라고 볼 수는 없다.
=> 배열 순회에는 for...of 또는 forEach 등을 사용하자..!
'Frontend > javascript' 카테고리의 다른 글
| [js] 표현식과 문, 데이터 타입 (0) | 2026.03.11 |
|---|---|
| [모던 Javascript DeepDive] 4. 변수 (0) | 2026.03.04 |
| [iframe 사용법 및 속성값 가이드] MDN 문서를 기반으로 작성한 가이드 문서 (2) | 2024.11.19 |
| [javascript] 생성자 함수는 어떤 과정으로 인스턴스를 생성할까? (2) | 2024.04.25 |
| [javascript] 생성자 함수에 의한 객체 생성 - 언제 필요하고 어떻게 사용하는가? (0) | 2024.04.18 |
댓글