우리는 종종 행동을 반복해야 합니다.
예를 들어, 목록에서 상품을 하나씩 출력하거나 1부터 10까지의 각 숫자에 대해 동일한 코드를 실행하는 것입니다.
루프는 동일한 코드를 여러 번 반복하는 방법입니다.
for…of 및 for…in 루프
고급 독자를 위한 작은 공지입니다.
이 문서에서는 while
, do..while
및 for(..;..;..)
기본 루프만 다룹니다.
다른 유형의 루프를 검색하여 이 문서를 방문했다면 다음 지침을 따르세요.
객체 속성을 반복하려면 for…in을 참조하세요.
배열과 반복 가능한 객체에 대한 반복은 for…of 및 반복 가능 항목을 참조하세요.
그렇지 않은 경우 계속 읽어보세요.
while
루프에는 다음과 같은 구문이 있습니다:
동안(조건) { // 코드 // 소위 "루프 본문" }
condition
이 참이면 루프 본문의 code
실행됩니다.
예를 들어, 아래 루프는 i
while i < 3
출력합니다.
내가 = 0이라고 하자; while (i < 3) { // 0, 1, 2를 표시합니다. 경고(i); 나++; }
루프 본문의 단일 실행을 반복 이라고 합니다. 위 예제의 루프는 세 번 반복됩니다.
위의 예에서 i++
누락된 경우 루프는 (이론적으로) 영원히 반복됩니다. 실제로 브라우저는 이러한 루프를 중지하는 방법을 제공하며 서버 측 JavaScript에서는 프로세스를 종료할 수 있습니다.
비교뿐만 아니라 모든 표현식이나 변수가 루프 조건이 될 수 있습니다. 조건은 while
에 의해 평가되고 부울로 변환됩니다.
예를 들어, while (i != 0)
작성하는 더 짧은 방법은 while (i)
입니다:
i = 3이라고 하자; while (i) { // i가 0이 되면 조건이 거짓이 되고 루프가 멈춥니다. 경고(i); 나--; }
단일 행 본문에는 중괄호가 필요하지 않습니다.
루프 본문에 단일 문이 있는 경우 중괄호 {…}
를 생략할 수 있습니다.
i = 3이라고 하자; (i) 경고(i--);
조건 확인은 do..while
구문을 사용하여 루프 본문 아래로 이동할 수 있습니다.
하다 { // 루프 본문 } while(조건);
루프는 먼저 본문을 실행한 다음 조건을 확인하고 그것이 사실인 동안 계속해서 실행합니다.
예를 들어:
내가 = 0이라고 하자; 하다 { 경고(i); 나++; } 동안(i < 3);
이 구문 형식은 조건이 참인지 여부에 관계없이 루프 본문을 한 번 이상 실행하려는 경우에만 사용해야 합니다. 일반적으로 다른 형식이 선호됩니다: while(…) {…}
.
for
루프는 더 복잡하지만 가장 일반적으로 사용되는 루프이기도 합니다.
다음과 같습니다:
for(시작; 조건; 단계) { // ... 루프 본문 ... }
이 부분의 의미를 예를 통해 알아봅시다. 아래 루프는 i
대해 0
에서 3
까지(포함하지 않음)에 대해 alert(i)
실행합니다.
for (let i = 0; i < 3; i++) { // 0, 1, 2를 표시합니다. 경고(i); }
for
문을 부분별로 살펴보겠습니다.
부분 | ||
---|---|---|
시작하다 | let i = 0 | 루프에 진입하면 한 번 실행됩니다. |
상태 | i < 3 | 모든 루프 반복 전에 확인됩니다. 거짓이면 루프가 중지됩니다. |
몸 | alert(i) | 조건이 참인 동안 계속해서 실행됩니다. |
단계 | i++ | 각 반복마다 본문 이후에 실행됩니다. |
일반적인 루프 알고리즘은 다음과 같이 작동합니다.
실행 시작 → (조건 → 실행 바디 및 실행 단계) → (조건 → 실행 바디 및 실행 단계) → (조건 → 실행 바디 및 실행 단계) → ...
즉, begin
한 번 실행된 다음 반복됩니다. 각 condition
테스트 후에 body
과 step
실행됩니다.
루프를 처음 사용하는 경우 예제로 돌아가서 종이에 단계별로 실행되는 방식을 재현하는 것이 도움이 될 수 있습니다.
우리의 경우에는 정확히 다음과 같은 일이 발생합니다.
// for (let i = 0; i < 3; i++) 경고(i) // 실행 시작 내가 = 0이라고 하자 // 조건이 있는 경우 → 본문 실행 및 단계 실행 if (i < 3) { 경고(i); 나++ } // 조건이 있는 경우 → 본문 실행 및 단계 실행 if (i < 3) { 경고(i); 나++ } // 조건이 있는 경우 → 본문 실행 및 단계 실행 if (i < 3) { 경고(i); 나++ } // ...완료, 이제 i == 3이기 때문입니다.
인라인 변수 선언
여기서는 "카운터" 변수 i
루프에서 바로 선언됩니다. 이를 "인라인" 변수 선언이라고 합니다. 이러한 변수는 루프 내부에서만 표시됩니다.
for (let i = 0; i < 3; i++) { 경고(i); // 0, 1, 2 } 경고(i); // 오류, 해당 변수가 없습니다.
변수를 정의하는 대신 기존 변수를 사용할 수 있습니다.
내가 = 0이라고 하자; for (i = 0; i < 3; i++) { // 기존 변수 사용 경고(i); // 0, 1, 2 } 경고(i); // 3, 루프 외부에서 선언되었으므로 표시됩니다.
for
의 모든 부분을 건너뛸 수 있습니다.
예를 들어, 루프 시작 시 아무것도 할 필요가 없으면 begin
생략할 수 있습니다.
여기처럼:
내가 = 0이라고 하자; // 이미 선언하고 할당했습니다. for (; i < 3; i++) { // "시작"이 필요하지 않습니다. 경고(i); // 0, 1, 2 }
step
부분을 제거할 수도 있습니다.
내가 = 0이라고 하자; (; i < 3;) { 경고(i++); }
이는 루프를 while (i < 3)
과 동일하게 만듭니다.
실제로 모든 것을 제거하여 무한 루프를 만들 수 있습니다.
을 위한 (;;) { // 제한 없이 반복 }
두 개는 세미콜론 for
해당합니다 ;
존재해야 합니다. 그렇지 않으면 구문 오류가 발생합니다.
일반적으로 루프는 조건이 거짓이 되면 종료됩니다.
하지만 특별한 break
지시문을 사용하면 언제든지 강제로 종료할 수 있습니다.
예를 들어, 아래 루프는 사용자에게 일련의 숫자를 요청하며, 숫자가 입력되지 않으면 "끊어집니다".
합계 = 0으로 둡니다. 동안 (참) { let value = +prompt("숫자를 입력하세요", ''); if (!value) 중단; // (*) 합계 += 값; } Alert( '합계: ' + 합 );
사용자가 빈 줄을 입력하거나 입력을 취소하면 해당 줄 (*)
에서 break
지시문이 활성화됩니다. 루프를 즉시 중지하고 루프 뒤의 첫 번째 줄에 제어권을 전달합니다. 즉, alert
.
"무한 루프 + 필요에 따라 break
" 조합은 루프의 시작이나 끝이 아니라 루프 본문의 중간이나 여러 위치에서 루프의 조건을 확인해야 하는 상황에 적합합니다.
continue
지시문은 break
의 "가벼운 버전"입니다. 전체 루프가 중지되지는 않습니다. 대신, 현재 반복을 중지하고 루프가 새 반복을 시작하도록 강제합니다(조건이 허용하는 경우).
현재 반복을 마치고 다음 반복으로 넘어가고 싶다면 이를 사용할 수 있습니다.
아래 루프는 continue
홀수 값만 출력하는 데 사용됩니다.
for (let i = 0; i < 10; i++) { // true인 경우 본문의 나머지 부분을 건너뜁니다. if (i % 2 == 0) 계속; 경고(i); // 1, 그다음 3, 5, 7, 9 }
i
값이 짝수인 경우 continue
지시문은 본문 실행을 중지하고 for
(다음 숫자 사용)의 다음 반복으로 제어를 전달합니다. 따라서 alert
홀수 값에 대해서만 호출됩니다.
continue
지시문은 중첩을 줄이는 데 도움이 됩니다.
홀수 값을 표시하는 루프는 다음과 같습니다.
for (let i = 0; i < 10; i++) { 만약 (i % 2) { 경고(i); } }
기술적인 관점에서 이는 위의 예와 동일합니다. 물론 continue
사용하는 대신 if
블록으로 코드를 래핑할 수 있습니다.
그러나 부작용으로 인해 중첩 수준이 한 단계 더 생성되었습니다(중괄호 내부의 alert
호출). if
내부의 코드가 몇 줄보다 길면 전체적인 가독성이 떨어질 수 있습니다.
break/continue
표현식이 아닌 구문 구성은 삼항 연산자 ?
와 함께 사용할 수 없습니다. . 특히 break/continue
와 같은 지시문은 허용되지 않습니다.
예를 들어, 다음 코드를 사용하면:
만약 (i > 5) { 경고(i); } 또 다른 { 계속하다; }
...그리고 물음표를 사용하여 다시 작성합니다.
(나는 > 5) ? 경고(i) : 계속; // 여기서 계속은 허용되지 않습니다.
...작동이 중지됩니다. 구문 오류가 있습니다.
이는 물음표 연산자를 사용하지 않는 또 다른 이유일 뿐입니다 ?
if
대신에 .
때로는 여러 중첩 루프에서 한 번에 벗어나야 할 때도 있습니다.
예를 들어, 아래 코드에서는 i
와 j
반복하여 (0,0)
에서 (2,2)
까지의 좌표 (i, j)
를 묻는 메시지를 표시합니다.
for (let i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { let input = 프롬프트(`좌표 값 (${i},${j})`, ''); // 여기서 종료하여 완료(아래)로 돌아가려면 어떻게 해야 할까요? } } Alert('완료!');
사용자가 입력을 취소하면 프로세스를 중지하는 방법이 필요합니다.
input
후 일반적인 break
내부 루프만 중단합니다. 그것만으로는 충분하지 않습니다. 레이블 여러분, 구조하러 오세요!
레이블은 루프 앞에 콜론이 있는 식별자입니다.
labelName: for (...) { ... }
아래 루프의 break <labelName>
문은 레이블로 분리됩니다.
외부: for (let i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { let input = 프롬프트(`좌표 값 (${i},${j})`, ''); // 빈 문자열이거나 취소된 경우 두 루프에서 모두 중단됩니다. if (!input) 외부 중단; // (*) // 값으로 뭔가를 합니다... } } Alert('완료!');
위 코드에서 break outer
outer
라는 레이블을 위쪽으로 찾고 해당 루프에서 빠져나옵니다.
따라서 제어는 (*)
에서 alert('Done!')
으로 바로 이동합니다.
레이블을 별도의 줄로 이동할 수도 있습니다.
밖의: for (let i = 0; i < 3; i++) { ... }
continue
지시문은 레이블과 함께 사용할 수도 있습니다. 이 경우 코드 실행은 레이블이 지정된 루프의 다음 반복으로 이동합니다.
라벨은 어디에서나 "점프"를 허용하지 않습니다.
레이블을 사용하면 코드의 임의 위치로 이동할 수 없습니다.
예를 들어 다음과 같은 작업은 불가능합니다.
브레이크 라벨; // 아래 라벨로 점프합니다(작동하지 않음) 라벨: (...)에 대해
break
지시문은 코드 블록 내에 있어야 합니다. 기술적으로 레이블이 지정된 코드 블록은 모두 가능합니다. 예:
라벨: { // ... 브레이크 라벨; // 작동 // ... }
...그러나 위의 예에서 볼 수 있듯이 시간 break
의 99.9%가 루프 내부에서 사용됩니다.
continue
루프 내부에서만 가능합니다.
우리는 3가지 유형의 루프를 다루었습니다:
while
– 각 반복 전에 조건을 확인합니다.
do..while
– 각 반복 후에 조건이 확인됩니다.
for (;;)
– 각 반복 전에 조건이 확인되며 추가 설정이 가능합니다.
"무한" 루프를 만들려면 일반적으로 while(true)
구문이 사용됩니다. 이러한 루프는 다른 루프와 마찬가지로 break
지시문을 사용하여 중지할 수 있습니다.
현재 반복에서 아무것도 하고 싶지 않고 다음 반복으로 전달하고 싶다면 continue
지시문을 사용할 수 있습니다.
루프 전에 break/continue
지원 레이블을 지정합니다. 레이블은 break/continue
중첩 루프를 탈출하여 외부 루프로 이동하는 유일한 방법입니다.
중요도: 3
이 코드에서 경고한 마지막 값은 무엇입니까? 왜?
i = 3이라고 하자; 동안 (i) { 경고( i-- ); }
대답: 1
.
i = 3이라고 하자; 동안 (i) { 경고( i-- ); }
모든 루프 반복은 i
1
씩 감소시킵니다. while(i)
검사는 i = 0
일 때 루프를 중지합니다.
따라서 루프의 단계는 다음 순서("루프 풀림")를 형성합니다.
i = 3이라고 하자; 경고(i--); // 3을 표시하고 i를 2로 감소시킵니다. Alert(i--) // 2를 표시하고 i를 1로 감소시킵니다. Alert(i--) // 1을 표시하고 i를 0으로 감소시킵니다. // 완료, while(i) 검사가 루프를 중지합니다.
중요도: 4
모든 루프 반복에 대해 출력되는 값을 기록한 다음 이를 솔루션과 비교하십시오.
두 루프 모두 동일한 값을 alert
합니까?
접두사 형식 ++i
:
내가 = 0이라고 하자; while (++i < 5) 경고(i );
접미사 형식 i++
내가 = 0이라고 하자; while (i++ < 5) 경고(i );
이 작업은 비교에 사용될 때 접미사/접두사 형식이 어떻게 다른 결과로 이어질 수 있는지 보여줍니다.
1부터 4까지
내가 = 0이라고 하자; while (++i < 5) 경고(i );
첫 번째 값은 i = 1
입니다. ++i
먼저 i
증가시킨 다음 새 값을 반환하기 때문입니다. 따라서 첫 번째 비교는 1 < 5
이고 alert
1
표시됩니다.
그런 다음 2, 3, 4…
따르세요. 값이 차례로 표시됩니다. ++
변수 앞에 있기 때문에 비교에서는 항상 증가된 값을 사용합니다.
마지막으로 i = 4
5
로 증가하고 while(5 < 5)
비교가 실패하며 루프가 중지됩니다. 따라서 5
표시되지 않습니다.
1부터 5까지
내가 = 0이라고 하자; while (i++ < 5) 경고(i );
첫 번째 값은 다시 i = 1
입니다. i++
의 후위 형식은 i
증가시킨 다음 이전 값을 반환하므로 i++ < 5
비교에서는 ( ++i < 5
와 반대로) i = 0
사용합니다.
하지만 alert
호출은 별개입니다. 이는 증가 및 비교 후에 실행되는 또 다른 명령문입니다. 따라서 현재 i = 1
얻습니다.
그런 다음 2, 3, 4…
i = 4
에서 멈추자. 접두사 형식 ++i
이를 증가시키고 비교에 5
사용합니다. 하지만 여기에는 i++
형식의 접미사가 있습니다. 따라서 i
5
로 증가시키지만 이전 값을 반환합니다. 따라서 비교는 실제로 while(4 < 5)
– true이고 컨트롤은 계속 alert
.
i = 5
값이 마지막 값입니다. 왜냐하면 다음 단계에서는 while(5 < 5)
false이기 때문입니다.
중요도: 4
각 루프에 대해 표시할 값을 적어 두세요. 그런 다음 답변과 비교하십시오.
두 루프 모두 동일한 값을 alert
합니까?
접미사 형식:
for (let i = 0; i < 5; i++) 경고( i );
접두사 형식:
for (let i = 0; i < 5; ++i) 경고( i );
답은 두 경우 모두 0
부터 4
까지입니다.
for (let i = 0; i < 5; ++i) 경고( i ); for (let i = 0; i < 5; i++) 경고( i );
이는 for
알고리즘에서 쉽게 추론할 수 있습니다.
모든 것(시작) 전에 i = 0
일 때 한 번만 실행합니다.
i < 5
조건을 확인하세요.
true
인 경우 루프 본문을 실행하고, alert(i)
실행한 다음 i++
실행합니다.
i++
증분은 조건 확인(2)과 분리됩니다. 그것은 또 다른 진술일 뿐입니다.
증분에 의해 반환된 값은 여기서 사용되지 않으므로 i++
와 ++i
사이에는 차이가 없습니다.
중요도: 5
for
루프를 사용하여 2
에서 10
까지의 짝수를 출력합니다.
데모 실행
for (let i = 2; i <= 10; i++) { if (i % 2 == 0) { 경고(i); } }
나머지를 구하고 여기에서 균등성을 확인하기 위해 "모듈로" 연산자 %
사용합니다.
중요도: 5
동작을 변경하지 않고 for
루프를 while
으로 변경하는 코드를 다시 작성합니다(출력은 동일하게 유지되어야 함).
for (let i = 0; i < 3; i++) { 경고( `번호 ${i}!` ); }
내가 = 0이라고 하자; 동안 (i < 3) { 경고( `번호 ${i}!` ); 나++; }
중요도: 5
100
보다 큰 숫자를 묻는 루프를 작성하세요. 방문자가 다른 번호를 입력하면 다시 입력하도록 요청하세요.
루프는 방문자가 100
보다 큰 숫자를 입력하거나 입력을 취소하거나 빈 줄을 입력할 때까지 숫자를 요청해야 합니다.
여기서는 방문자가 숫자만 입력한다고 가정할 수 있습니다. 이 작업에서는 숫자가 아닌 입력에 대해 특별한 처리를 구현할 필요가 없습니다.
데모 실행
숫자를 보자; 하다 { num = 프롬프트("100보다 큰 숫자를 입력하시겠습니까?", 0); } while (num <= 100 && num);
루프 do..while
은 두 검사가 모두 진실인 동안 반복됩니다.
num <= 100
인지 확인합니다. 즉, 입력된 값이 여전히 100
보다 크지 않습니다.
num
이 null
이거나 빈 문자열인 경우 && num
검사는 false입니다. 그런 다음 while
루프도 중지됩니다.
PS num
이 null
이면 num <= 100
이 true
이므로 두 번째 확인이 없으면 사용자가 취소를 클릭해도 루프가 중지되지 않습니다. 두 가지 확인이 모두 필요합니다.
중요도: 3
1
보다 큰 정수를 1
과 자기 자신 이외의 어떤 것으로도 나머지 없이 나눌 수 없으면 소수라고 합니다.
즉, n > 1
1
과 n
외에는 균등하게 나누어질 수 없는 경우 소수입니다.
예를 들어, 5
2
, 3
, 4
로 나머지 없이 나눌 수 없기 때문에 소수입니다.
2
부터 n
까지의 구간에서 소수를 출력하는 코드를 작성하세요.
n = 10
의 경우 결과는 2,3,5,7
입니다.
PS 코드는 모든 n
에 대해 작동해야 하며 고정 값에 대해 하드 튜닝되어서는 안 됩니다.
이 작업에는 많은 알고리즘이 있습니다.
중첩 루프를 사용해 보겠습니다.
간격 {의 각 i에 대해 1..i의 제수가 있는지 확인하세요. 그렇다면 => 값은 소수가 아닙니다. 아니요 => 값이 소수이면 표시합니다. }
라벨을 사용하는 코드:
n = 10이라고 하자; 다음프라임: for (let i = 2; i <= n; i++) { // 각 i에 대해... for (let j = 2; j < i; j++) { // 제수를 찾습니다.. if (i % j == 0) nextPrime을 계속합니다; // 소수가 아닙니다. 다음으로 가세요. } 경고(i); // 소수 }
최적화할 수 있는 여지가 많습니다. 예를 들어, 2
에서 i
의 제곱근까지의 약수를 찾을 수 있습니다. 그러나 어쨌든 큰 간격에 대해 정말 효율적이기를 원한다면 접근 방식을 변경하고 이차 체, 일반 수 필드 체 등과 같은 고급 수학 및 복잡한 알고리즘에 의존해야 합니다.