while

while

while 문은 테스트 조건이 true로 평가되는 동안 지정된 문을 실행하는 루프를 만듭니다. 조건은 문을 실행하기 전에 평가됩니다.

출처: while

본문

while 문은 테스트 조건이 true로 평가되는 동안 지정된 문을 실행하는 루프를 만듭니다. 조건은 문을 실행하기 전에 평가됩니다. 이 기능은 널리 확립되어 있으며 여러 브라우저에서 지원됩니다.

구문 (Syntax)

while (condition)
  statement
  • condition: 루프를 통과할 때마다 평가되는 표현식입니다. 이 조건이 true로 평가되면 statement가 실행됩니다. conditionfalse로 평가되면 실행은 while 루프 다음의 문으로 계속됩니다.
  • statement: 조건이 true로 평가되는 동안 실행되는 문입니다. 여러 문을 실행하려면 블록 문을 사용하세요.

설명 (Description)

다른 루핑 문과 마찬가지로, statement 내부에서 제어 흐름 문을 사용할 수 있습니다.

  • break는 문 실행을 중단하고 루프 다음의 첫 번째 문으로 갑니다.
  • continue는 문 실행을 중단하고 condition을 재평가합니다.

예제: while 사용하기

다음 while 루프는 n이 3보다 작은 동안 반복합니다.

let n = 0;
let x = 0;

while (n < 3) {
  n++;
  x += n;
}

각 반복마다 루프는 n을 증가시키고 이를 x에 더합니다. 따라서 xn은 다음 값들을 갖습니다.

  • 첫 통과 후: n = 1 및 x = 1
  • 두 번째 통과 후: n = 2 및 x = 3
  • 세 번째 통과 후: n = 3 및 x = 6

세 번째 통과를 마친 후 조건 n < 3이 더 이상 true가 아니므로 루프가 종료됩니다.

예제: 조건으로 할당(assignment) 사용하기

어떤 경우에는 조건으로 할당을 사용하는 것이 합리적일 수 있습니다. 이는 가독성 tradeoff를 수반하므로 패턴을 모두에게 더 명확하게 만드는 몇 가지 스타일 권장사항이 있습니다.

문서의 주석을 반복하며 콘솔에 로그하는 다음 예제를 고려해 보세요.

const iterator = document.createNodeIterator(document, NodeFilter.SHOW_COMMENT);
let currentNode;
while (currentNode = iterator.nextNode()) {
  console.log(currentNode.textContent.trim());
}

이것은 특히 다음 줄 때문에 완전히 좋은 습관의 예제는 아닙니다.

while (currentNode = iterator.nextNode()) {

그 줄의 효과는 괜찮습니다. 주석 노드가 발견될 때마다:

  • iterator.nextNode()가 그 주석 노드를 반환하고, 이것이 currentNode에 할당됩니다.
  • 따라서 currentNode = iterator.nextNode()의 값은 truthy입니다.
  • 그래서 console.log() 호출이 실행되고 루프가 계속됩니다.

...그리고 문서에 주석 노드가 더 이상 없을 때:

  • iterator.nextNode()null을 반환합니다.
  • 따라서 currentNode = iterator.nextNode()의 값도 null이며 falsy입니다.
  • 그래서 루프가 끝납니다.

이 줄의 문제는 조건이 보통 === 같은 비교 연산자를 사용한다는 점입니다. 그러나 그 줄의 =는 비교 연산자가 아니라 할당 연산자입니다. 그래서 그 =이 실제 오타가 아님에도 ===의 오타처럼 보입니다.

따라서 그런 경우에 ESLint의 no-cond-assign 규칙 같은 일부 코드 린팅 도구는 가능한 오타를 잡아 고칠 수 있도록 다음과 같은 경고를 보고합니다.

Expected a conditional expression and instead saw an assignment.

많은 스타일 가이드가 할당임을 의도했음을 더 명시적으로 나타낼 것을 권장합니다. 할당 주위에 그룹 연산자로 추가 괄호를 넣어 최소한으로 할 수 있습니다.

const iterator = document.createNodeIterator(document, NodeFilter.SHOW_COMMENT);
let currentNode;
while ((currentNode = iterator.nextNode())) {
  console.log(currentNode.textContent.trim());
}

사실 이 스타일은 ESLint의 no-cond-assign 기본 설정과 Prettier가 강제하는 스타일이므로, 실제 코드에서 이 패턴을 자주 보게 될 것입니다.

어떤 사람들은 비교 연산자를 추가해 조건을 명시적 비교로 바꾸는 것을 추가로 권장하기도 합니다.

while ((currentNode = iterator.nextNode()) !== null) {

이 패턴을 쓰는 다른 방법도 있습니다.예:

while ((currentNode = iterator.nextNode()) && currentNode) {

또는 while 루프 아이디어 자체를 포기할 수도 있습니다.

const iterator = document.createNodeIterator(document, NodeFilter.SHOW_COMMENT);
for (
  let currentNode = iterator.nextNode();
  currentNode;
  currentNode = iterator.nextNode()
) {
  console.log(currentNode.textContent.trim());
}

더 알아보기