>웹 프론트엔드 >JS 튜토리얼 >기능적 자바 스크립트의 재귀

기능적 자바 스크립트의 재귀

Joseph Gordon-Levitt
Joseph Gordon-Levitt원래의
2025-02-19 10:22:09341검색

Recursion in Functional JavaScript 당신은 JavaScript의 재귀 기능에 대해 들었을 수도 있고, 심지어 일부는 글을 쓰려고했을 수도 있습니다. 그러나 당신은 실제로 작동하는 재귀의 많은 예를 보지 못했을 것입니다. 실제로,이 접근법의 특수성 외에, 재귀가 언제 어디서 유용한시기와 장소 또는 부적절하게 사용하는 경우 얼마나 위험한 지 고려하지 않았을 수도 있습니다.

키 포인트

재귀는 결과에 도달 할 때까지 기능을 반복적으로 호출 할 수있는 JavaScript 방법입니다. 프랙탈 수학, 정렬 또는 복잡한 비선형 데이터 구조와 같은 반복 분기와 관련된 문제에 특히 유용합니다. 재귀는 코드를보다 간결하고 이해하기 쉽게 만들 수 있지만 부적절하게 사용하면 엔진의 메모리 용량을 초과 할 위험이 있기 때문에 위험 할 수 있습니다. JavaScript 재귀 함수는 올바른 장소에서 계속 실행할 수 있도록 매번 전화를받는 위치를 추적해야하기 때문입니다. 많은 기능적 프로그래밍 언어에서 Tail Call Optimization이라는 기술이 재귀를 관리하는 데 사용됩니다. 이를 통해 재귀 함수의 각 연속 루프는 메모리에 쌓이지 않고 즉시 발생할 수 있습니다. 그러나 대부분의 JavaScript 컴파일러는 아직 최적화되지 않았습니다.

사용자 정의 바운스 함수는 재귀 실행을 반복적으로 관리하기 위해 구축 할 수 있으며 한 번에 스택에 하나의 작업 만 남습니다. 이는 성능과 가독성을 희생시키면서 대기 대기 대기 대기중인 스택 작업을 피하는 데 도움이 될 수 있습니다.
  • 재귀 목적
  • 재귀는 결과가 얻어 질 때까지 함수 호출 자체를 반복적으로 호출함으로써 작동을 통해 반복하는 기술입니다. 대부분의 루프는 재귀 스타일로 다시 작성할 수 있으며 일부 기능 프로그래밍 언어에서는이 루프 방법이 기본값입니다.
  • 그러나 JavaScript의 기능 프로그래밍 스타일은 재귀 기능을 지원하지만 대부분의 JavaScript 컴파일러는 현재 안전하게 최적화되지 않았 음을 알아야합니다.
  • 재귀는 루프에서 다른 매개 변수로 동일한 함수를 반복적으로 호출해야 할 때 가장 잘 사용됩니다. 많은 경우에 사용될 수 있지만, 복잡한 수학 또는 비선형 데이터 구조의 노드를 정렬하거나 통과하는 반복 분기와 관련된 문제를 해결하는 데 가장 효과적입니다.
  • 기능적 프로그래밍 언어에서 재귀가 선호되는 이유 중 하나는 상태를 설정하고 유지하기 위해 로컬 변수를 사용하지 않는 건축 코드를 허용하기 때문입니다. 재귀 함수는 순수한 방식으로 쓰기 쉽고, 주어진 입력에 대해 구체적이고 일관된 반환 값을 가지며 외부 변수의 상태에 부작용이 없기 때문에 테스트하기가 쉽습니다.
  • 사이클
재귀를 적용 할 수있는 전형적인 기능 예는 요인입니다. 이것은 숫자의 결과를 각각의 각 정수를 반복적으로 곱한 결과를 1로 반복하는 함수입니다.

예를 들어, 3의 계승은 다음과 같습니다 6의 요인은 다음과 같습니다

<code>3 × 2 × 1 = 6</code>
이 결과가 얼마나 빨리 더 커지는 지 알 수 있습니다. 또한 우리가 같은 행동을 반복해서 반복하는 것을 볼 수 있습니다. 우리는 곱셈 작업의 결과를 취하고 두 번째 값을 마이너스 1에 곱합니다. 그런 다음 우리는 1에 도달 할 때까지 계속 해서이 작업을 수행합니다.

for 루프를 사용하여 올바른 결과가 반환 될 때 까지이 작업을 반복하는 함수를 만드는 것은 어렵지 않습니다.

이것은 작동하지만 기능적 프로그래밍 관점에서 우아하지는 않습니다. For Loop을 지원 한 다음 결과를 반환하려면 상태를 유지하고 추적하는 여러 로컬 변수를 사용해야합니다. For Loop을 폐기하고보다 기능적인 JavaScript 방법을 채택 할 수 있다면 더 간결하지 않습니까?

재귀

우리는 JavaScript를 통해 기능을 매개 변수로 취하는 함수를 쓸 수 있습니다. 그렇다면 우리가 쓰는 실제 함수를 사용하고 그것을 실행하는 상황에서 실행하려면 어떻게해야합니까?
<code>6 × 5 × 4 × 3 × 2 × 1 = 720</code>
이것은 가능합니까? 확신하는! 예를 들어, 이러한 간단한 While 루프를 고려하십시오 :

이 작업이 완료된 후 카운터의 값이 변경되었지만 루프는 각 값을 인쇄하는 작업을 완료했습니다.

동일한 루프의 재귀 버전은 다음과 같이 보일 수 있습니다.

카운트 다운 함수의 정의에서 카운트 다운 함수를 직접 호출하는 방법을 보셨습니까? JavaScript는 보스처럼 처리하고 원하는대로 만 수행합니다. 카운트 다운이 실행될 때마다 JavaScript가 호출되는 위치를 추적 한 다음 해당 기능 호출의 스택으로 돌아갑니다. 우리의 기능은 또한 변수의 상태를 수정하는 것을 피하지만 전달 된 값을 사용하여 재귀를 제어합니다. 우리의 계승 사례로 돌아가서, 우리는 재귀를 사용하기 위해 이와 같은 이전 기능을 다시 작성할 수 있습니다 : .

이런 방식으로 코드를 작성하면 부작용없이 전체 프로세스를 무국적 방식으로 설명 할 수 있습니다. 또한 먼저 기능에 전달 된 매개 변수의 값을 테스트 한 다음 계산을 수행한다는 점도 주목할 가치가 있습니다. 우리는 종료에 도달 할 때 빠르고 깨끗하게 종료하기 위해 전화를 걸려는 기능을 원합니다. 이러한 방식으로 계산 된 요인의 경우, 들어오는 숫자가 0 또는 음수 일 때 종료 상황에 도달합니다 (원한다면 음수 값을 테스트하고 다른 메시지를 반환 할 수도 있습니다).

테일 호출 최적화

현대 JavaScript 구현의 문제 중 하나는 재귀 기능이 엔진의 용량을 초과 할 때까지 재귀 함수가 무한대로 쌓이고 메모리를 소비하는 것을 방지하는 표준 방법이 없다는 것입니다. JavaScript 재귀 함수는 매번 전화를받는 위치를 추적하여 올바른 장소에서 계속 실행할 수 있어야합니다.
<code class="language-javascript">var factor = function(number) {
  var result = 1;
  var count;
  for (count = number; count > 1; count--) {
    result *= count;
  }
  return result;
};
console.log(factor(6));
// 720</code>
Haskell 및 Scheme과 같은 많은 기능 프로그래밍 언어에서 이것은 Tail Call Optimization이라는 기술을 사용하여 관리됩니다. 테일 콜 최적화를 사용하면 재귀 함수의 각 연속 루프가 메모리에 쌓이지 않고 즉시 발생합니다.

이론적으로 Tail Call 최적화는 ECMAScript 6 (현재 JavaScript의 다음 버전) 표준의 일부이지만 대부분의 플랫폼은 아직 완전히 구현되지 않았습니다.

바운스 함수

필요한 경우 JavaScript가 재귀 기능을 안전한 방식으로 실행하도록하는 방법이 있습니다. 예를 들어, 사용자 정의 바운스 기능을 구축하여 재귀 실행을 반복적으로 관리하여 한 번에 스택에 하나의 작업 만 남겨 둘 수 있습니다. 이러한 방식으로 사용 된 바운스 함수는 재귀 함수를 다시 튕기기 위해 기능을 특정 컨텍스트에 바인딩하는 JavaScript의 능력을 활용하여 루프가 완료 될 때까지 결과를 한 번에 하나씩 구축 할 수 있습니다. 이렇게하면 실행을 기다리는 깊은 스택 작업이 발생하지 않습니다.

실제로 튀는 기능을 사용하면 안전을위한 성능이 줄어 듭니다. 또한,이 접근 방식이 JavaScript로 작동하도록하는 데 필요한 코드 컨볼 루션에서 작문 기능을 통해 우리가 얻는 대부분의 우아함과 가독성이 손실됩니다.

당신이 궁금하다면, 나는 당신 이이 개념에 대해 더 많이 읽고 아래 토론에서 당신의 생각을 나누도록 권장합니다. StackoverFlow의 짧은 주제로 시작하여 Don Taylor와 Mark McDonnell의 일부 기사를 탐색하여 JavaScript의 반동 기능의 장단점에 더 깊이 들어갑니다.

우리는 아직 그 시점에 있지 않습니다 재귀는 알 가치가있는 강력한 기술입니다. 대부분의 경우 재귀는 복잡한 문제를 해결하는 가장 간단한 방법입니다. 그러나 ECMAScript 6이 필요한 위치에 테일 콜 최적화를 완전히 구현하기 전에 재귀 적 적용 방법과 위치에 대해 매우주의해야합니다.

기능적 자바 스크립트 (FAQS)의 재귀에 대한 FAQ 재귀의 기본 상황은 무엇입니까? 왜 중요한가요?

재귀의 기본 상황은 함수가 자체를 무한대로 호출하는 것을 방지하는 조건입니다. 재귀 함수가 자체를 무한대로 호출하여 스택 오버플로 오류를 일으키기 때문에 중요합니다. 기본 상황은 일반적으로 재귀적인 호출을하기 전에 함수가 확인하는 조건입니다. 이 조건이 충족되면 함수는 값을 반환하고 스스로 호출을 중지합니다.

재귀는 JavaScript에서 어떻게 작동합니까? JavaScript에서, 재귀는 기본 상황에 도달 할 때까지 함수 자체를 호출하여 작동합니다. 이 기능은 기본 사례 및 재귀 사례로 나뉩니다. 기본 케이스는 함수를 다시 호출하지 않고 값을 반환하는 반면 재귀 케이스는 다른 매개 변수로 함수를 다시 호출합니다. 기본 케이스에 도달 할 때까지 함수는 계속 호출합니다.이 시점에서 값을 반환하기 시작합니다. JavaScript의 Tail Recursion이란 무엇입니까?

테일 재귀는 재귀 호출이 기능의 마지막 작업 인 특수 유형의 재귀입니다. Tail Call Optimization이라는 기술을 사용하여 JavaScript 엔진 최적화가 재발 할 수 있기 때문에 중요합니다. 이렇게하면 함수가 사용하는 메모리의 양을 크게 줄여 더 큰 입력을 처리 할 수 ​​있습니다.

JavaScript에서 재귀 사용의 장점과 단점은 무엇입니까?

재귀는 복잡한 문제를 더 간단한 문제로 나누어 코드를보다 간결하고 이해하기 쉽게 만들 수 있습니다. 트리 데이터 구조를 통과하는 것과 같은 작업에 특히 유용합니다. 그러나 재귀는 또한 반복 솔루션보다 효율적이지 않을 수 있으며, 잘못 구현하면 스택 오버플로 오류가 발생할 수 있습니다.

재귀 함수에서 스택 오버 플로 오류를 피하는 방법은 무엇입니까?

재귀 함수가 너무 많은 시간을 호출하고 통화 스택을 채우면 스택 오버플로 오류가 발생합니다. 이를 피하려면 재귀 기능에 결국 도달 할 기본 사례가 있는지 확인하십시오. 또한 JavaScript 엔진이 메모리를 적게 사용할 수 있도록 최적화 할 수있는 Tail Recursion을 사용하는 것을 고려하십시오.

기능적 프로그래밍에 재귀는 어떻게 사용됩니까?

기능적 프로그래밍에서 재귀는 종종 루프 대체물로 사용됩니다. 기능적 프로그래밍은 가변 상태의 사용을 권장하지 않기 때문에 재귀는 상태를 변경하지 않고 반복적 인 작업을 수행하는 데 사용될 수 있습니다.

모든 재귀 함수를 반복 함수로 변환 할 수 있습니까?

예, 이론적으로 모든 재귀 함수는 반복 함수로 변환 될 수 있습니다. 그러나 반복 버전은 특히 복잡한 트리 또는 그래프 트래버스와 관련된 기능에 대해 더 복잡하고 이해하기 어려울 수 있습니다.

JavaScript의 상호 재귀 란 무엇입니까?

상호 재귀는 루프에서 서로 호출되는 둘 이상의 함수를 말합니다. 이것은 특정 유형의 문제를 해결하는 강력한 기술 일 수 있지만 간단한 재귀보다 이해하고 디버깅하기가 더 어려울 수도 있습니다.

JavaScript에서 재귀 함수를 디버그하는 방법은 무엇입니까?

반복적 인 기능 호출로 인해 재귀 함수 배수가 어려울 수 있습니다. 그러나 console.log 문을 사용하여 각 단계에서 함수의 매개 변수와 리턴 값을 인쇄하는 것이 도움이 될 수 있습니다. 또한 기능 통화를 단계별로 수행 할 수있는 디버거 도구를 사용하는 것이 매우 유용합니다.

재귀를 사용할 때 성능 고려 사항이 있습니까?

예, 재귀 함수는 반복적 인 함수 호출의 오버 헤드로 인해 반복적 인 상대만큼 효율적이지 않을 수 있습니다. 그들이 너무 많은 시간을 부르면 스택 오버플로 오류를 일으킬 수도 있습니다. 그러나, 많은 경우에, 재귀 솔루션의 가독성과 단순성은 이러한 성능 고려 사항을 능가 할 수있다.

위 내용은 기능적 자바 스크립트의 재귀의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.