for
for
for 문은 괄호로 둘러싸고 세미콜론으로 구분한 세 개의 선택적 표현식으로 구성된 루프를 만들고, 뒤이어 루프에서 실행할 문(보통 블록 문)이 옵니다.
출처: for
본문
for 문은 괄호로 둘러싸고 세미콜론으로 구분한 세 개의 선택적 표현식(initialization, condition, afterthought)으로 구성된 루프를 만들고, 뒤이어 루프에서 실행할 문(보통 블록 문)이 옵니다.
구문 (Syntax)
for (initialization; condition; afterthought)
statement
initialization: 루프가 시작되기 전에 한 번 평가되는 표현식(할당 표현식 포함) 또는 변수 선언입니다. 보통 카운터 변수를 초기화하는 데 사용됩니다.var또는let키워드로 새 변수를 선택적으로 선언할 수 있습니다.var로 선언된 변수는 루프에 국한되지 않아for루프와 같은 스코프에 있습니다.let으로 선언된 변수는 문에 국한됩니다. 이 표현식의 결과는 버려집니다.condition: 각 루프 반복 전에 평가되는 표현식입니다. 이 표현식이true로 평가되면statement가 실행되고,false로 평가되면 실행이 루프를 빠져나가for구조 다음의 첫 번째 문으로 갑니다. 이 조건 테스트는 선택적이며, 생략하면 조건이 항상true로 평가됩니다.afterthought: 각 루프 반복의 끝에서 평가되는 표현식입니다.condition의 다음 평가 전에 발생합니다. 일반적으로 카운터 변수를 갱신하거나 증가시키는 데 사용됩니다.statement: 조건이true로 평가되는 동안 실행되는 문입니다. 여러 문을 실행하려면 블록 문을 사용하세요. 루프 내에서 아무 문도 실행하지 않으려면 빈 문(;)을 사용하세요.
설명 (Description)
다른 루핑 문과 마찬가지로, statement 내부에서 제어 흐름 문을 사용할 수 있습니다.
break는 문 실행을 중단하고 루프 다음의 첫 번째 문으로 갑니다.continue는 문 실행을 중단하고afterthought를 재평가한 다음condition을 재평가합니다.
예제: for 사용하기
다음 for 문은 변수 i를 선언하고 0으로 초기화하는 것으로 시작합니다. i가 9보다 작은지 확인하고, 두 개의 후속 문을 실행하며, 루프를 한 번 통과할 때마다 i를 1씩 증가시킵니다.
for (let i = 0; i < 9; i++) {
console.log(i);
// more statements
}
초기화 블록 구문
초기화 블록은 표현식과 변수 선언을 모두 허용합니다. 그러나 표현식은 괄호 없이 in 연산자를 사용할 수 없는데, 이는 for...in 루프와 모호하기 때문입니다.
for (let i = "start" in window ? window.start : 0; i < 9; i++) {
console.log(i);
}
// SyntaxError: 'for-in' loop variable declaration may not have an initializer.
괄호를 사용해 해결할 수 있습니다.
// Parenthesize the whole initializer
for (let i = ("start" in window ? window.start : 0); i < 9; i++) {
console.log(i);
}
선택적 for 표현식
for 루프 머리의 세 표현식 모두 선택적입니다. 예를 들어 초기화 블록을 사용해 변수를 초기화할 필요는 없습니다.
let i = 0;
for (; i < 9; i++) {
console.log(i);
}
조건 부분도 선택적입니다. 이 표현식을 생략하면 무한 루프를 만들지 않도록 본문에서 반드시 루프를 break해야 합니다.
for (let i = 0; ; i++) {
console.log(i);
if (i > 3) break;
// more statements
}
세 표현식을 모두 생략할 수도 있습니다. 다시 한번 루프를 끝내기 위해 break 문을 사용하고, break 문의 조건이 어떤 시점에서 true가 되도록 변수를 수정(증가)해야 합니다.
let i = 0;
for (;;) {
if (i > 3) break;
console.log(i);
i++;
}
그러나 세 표현식 위치를 모두 완전히 사용하지 않는 경우(특히 첫 번째 표현식으로 변수를 선언하지 않고 상위 스코프의 무언가를 변경하는 경우)에는 while 루프를 사용하는 것을 고려하세요. 의도가 더 명확해집니다.
초기화 블록의 어휘적 선언
초기화 블록에서 변수를 선언하는 것은 상위 스코프에서 선언하는 것과 중요한 차이가 있습니다. 특히 루프 본문 내에서 클로저를 만들 때 그렇습니다.
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
이 코드는 예상대로 0, 1, 2를 로그합니다. 그러나 변수가 상위 스코프에 정의되어 있으면:
let i = 0;
for (; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
3, 3, 3을 로그합니다. 그 이유는 각 setTimeout이 i 변수를 닫는 새 클로저를 만들지만, i가 루프 본문에 스코프되지 않으면 모든 클로저가 결국 호출될 때 같은 변수를 참조하게 되기 때문입니다. setTimeout()의 비동기 특성상 호출은 루프가 이미 종료된 후에 일어나므로, 대기 중인 모든 콜백 본문의 i 값이 3이 됩니다.
var 문을 초기화로 사용해도 같은 일이 발생합니다. var로 선언된 변수는 함수 스코프만 있고 어휘적 스코프가 없기(즉 루프 본문에 스코프될 수 없기) 때문입니다.
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
// Logs 3, 3, 3
초기화 블록의 스코프 효과는 선언이 루프 본문 내에서 발생하되, 마침 condition과 afterthought 부분에서 접근 가능한 것처럼 이해할 수 있습니다. 더 정확히 말하면, let 선언은 for 루프에 의해 특별 처리됩니다. 초기화가 let 선언이면 매번 루프 본문이 평가된 후 다음이 발생합니다.
- 새
let선언 변수를 가진 새 어휘 스코프가 생성됩니다. - 마지막 반복의 바인딩 값이 새 변수를 다시 초기화하는 데 사용됩니다.
afterthought가 새 스코프에서 평가됩니다.
따라서 afterthought 내에서 새 변수를 재할당해도 이전 반복의 바인딩에는 영향을 주지 않습니다.
본문 없는 for 사용하기
다음 for 주기는 afterthought 섹션에서 노드의 오프셋 위치를 계산하므로 문 섹션이 필요하지 않고, 대신 세미콜론이 사용됩니다.
function showOffsetPos(id) {
let left = 0;
let top = 0;
for (
let itNode = document.getElementById(id); // initialization
itNode; // condition
left += itNode.offsetLeft,
top += itNode.offsetTop,
itNode = itNode.offsetParent // afterthought
); // semicolon
console.log(
`Offset position of "${id}" element:
left: ${left}px;
top: ${top}px;`,
);
}
showOffsetPos("content");
for 문 뒤의 세미콜론은 필수입니다. 빈 문(empty statement)으로 서 있기 때문입니다. 그렇지 않으면 for 문이 다음 console.log 줄을 자신의 문 섹션으로 삼아 로그가 여러 번 실행됩니다.
두 개의 반복 변수를 가진 for 사용하기
쉼표 연산자(comma operator)를 사용해 for 루프에서 동시에 갱신되는 두 개의 카운터를 만들 수 있습니다. 여러 let 및 var 선언도 쉼표로 결합할 수 있습니다.
const arr = [1, 2, 3, 4, 5, 6];
for (let l = 0, r = arr.length - 1; l < r; l++, r--) {
console.log(arr[l], arr[r]);
}
// 1 6
// 2 5
// 3 4