자바 스크립트 : 재귀 익명 함수?


120

기본 재귀 함수가 있다고 가정 해 보겠습니다.

function recur(data) {
    data = data+1;
    var nothing = function() {
        recur(data);
    }
    nothing();
}

다음과 같은 익명 기능이 있으면 어떻게 할 수 있습니까?

(function(data){
    data = data+1;
    var nothing = function() {
        //Something here that calls the function?
    }
    nothing();
})();

이 함수를 호출하는 함수를 호출하는 방법을 원합니다. 호출 된 함수의 이름을 알려줄 수있는 스크립트를 어딘가에서 보았습니다 (어디에서 기억 나지 않음). 그 정보를 지금 당장.


이것이 필요한 이유가 있습니까, 아니면 그냥 궁금하십니까? 단순히 이름을 지정하는 것이 더 명확 할 것 같습니다 ...
rfunduk

1
@thenduks : 익명 함수를 사용하는 것과 같은 이유 때문입니다. 때때로 재귀가 필요합니다.
찌르기

5
부끄러운 arguments.callee일이며이 기능은 유용한 일을하지 않습니다. 나는 Y 결합자를 찾고 있었다 :P. 젠장, 그 재료는 것입니다 결코 ... 유용한 얻을
코비

1
네, Kobi가 링크했듯이 Y와 같은 고정 소수점 결합자를 사용하여 인수없이 익명의 재귀 함수를 수행합니다.
steamer25

1
JS의 Y 결합기 예제는 w3future.com/weblog/stories/2002/02/22/… 를 참조하십시오 .
steamer25

답변:


145

함수를 "함수 선언"문이 아닌 값으로 생성하는 경우에도 함수에 이름을 지정할있습니다 . 다시 말해:

(function foo() { foo(); })();

스택 블로잉 재귀 함수입니다. 즉, Javascript의 다양한 구현에 이상한 문제가 있기 때문에 일반적으로 이것을 원하지 않을 수도 있습니다 . ( 참고 -꽤 오래된 댓글입니다. Kangax의 블로그 게시물에 설명 된 일부 / 다수 / 모든 문제는 최신 브라우저에서 수정 될 수 있습니다.)

이와 같은 이름을 지정하면 이름이 함수 외부에 표시되지 않습니다 (글쎄, 그렇게되어서는 안됩니다. 그것은 이상한 점 중 하나입니다). Lisp의 "letrec"과 같습니다.

에 관해서 arguments.callee는 약간의 최적화를 어렵게하기 때문에, 나쁜 일을 생각된다 일반적으로 "엄격"모드에서 허용하고있어 그. 또한 예상보다 훨씬 느립니다.

edit — 자신을 호출 할 수있는 "익명"함수의 효과를 얻으려면 다음과 같이 할 수 있습니다 (함수를 콜백 또는 이와 유사한 것으로 전달한다고 가정).

asyncThingWithCallback(params, (function() {
  function recursive() {
    if (timeToStop())
      return whatever();
    recursive(moreWork);
  }
  return recursive;
})());

그것이하는 일은 멋지고 안전하며 IE에서 깨지지 않는 함수 선언문 으로 함수를 정의하여 이름이 전역 네임 스페이스를 오염시키지 않는 로컬 함수를 만드는 것입니다. 래퍼 (진정한 익명) 함수는 해당 로컬 함수를 반환합니다.


ES5 sctrict를 사용하여 글로벌 네임 스페이스를 다른 방식으로 오염시키는 것을 피할 수 있습니까 (아직 ES5에 대해 자세히 읽지 않았습니다)?
Incognito

@pointy이 질문을 봐주세요. stackoverflow.com/questions/27473450/…
Gladson Robinson

(() => { call_recursively_self_here() })()재귀 적 으로 사용 하고 호출 하는 것이 불가능하다고 생각합니다 . 이름을 정해야합니다.
Qwerty

1
@Qwerty 잘 당신은 내 대답의 마지막 예와 같은 것을 할 수 있습니다. 화살표 함수가 변수 이름으로 자신을 참조 할 수 있도록 래퍼 함수의 지역 변수에 화살표 함수를 바인딩합니다. 그런 다음 래퍼는 변수 (화살표 함수를 나타냄)를 반환합니다.
Pointy

1
어쩌면 일부 해커는 응용 프로그램을 찾을 수 @Pointy)
카밀 Kiełczewski

31

사람들은 코멘트에서 Y 결합 자에 대해 이야기했지만 아무도 답으로 작성하지 않았습니다.

Y 결합자는 다음과 같이 자바 스크립트로 정의 할 수 있습니다 : (링크에 대한 steamer25에게 감사드립니다)

var Y = function (gen) {
  return (function(f) {
    return f(f);
  }(function(f) {
    return gen(function() {
      return f(f).apply(null, arguments);
    });
  }));
}

익명 함수를 전달하려는 경우 :

(Y(function(recur) {
  return function(data) {
    data = data+1;
    var nothing = function() {
      recur(data);
    }
    nothing();
  }
})());

이 솔루션에 대해 주목해야 할 가장 중요한 점은 사용하지 않아야한다는 것입니다.


16
"이 솔루션에 대해 주목해야 할 가장 중요한 점은 사용하지 않아야한다는 것입니다." 왜?
nyuszika7h

7
빠르지 않을 것입니다. 실제로 사용하는 것은 추합니다 (개념적으로 아름답지만!). 함수에 태그 나 변수 이름을 지정하지 않아도되지만 (그게 문제가되는 이유는 모르겠지만) Y에 전달 된 외부 함수에 대한 매개 변수로 이름을 지정합니다. 이 모든 문제를 겪음으로써 무엇이든 얻을 수 있습니다.
zem

이 기능은 스택에 안전하지 않다는 것을 잊지 마십시오. 수천 번만 반복하면 스택 오버플로가 발생합니다.
감사합니다

안녕, 나는 .apply (null, arguments)가 나에게 못 생겼기 때문에 약간 "더 깨끗한"수정을 제안 할 것이다. var Y = function (gen) {return (function (f) {return f (f);} (function (f) {return gen (function (x) {return f (f) (x);});})); } 또는 화살표 표기법 (유효한 js 코드)을 사용하여 ((function (x) {return y} = (x => y))) : var Y = gen => (f => f (f)) (f = > gen (x => f (f) (x)))
myfirstAnswer

23

U 결합 자

함수를 인자로 자신에게 전달함으로써 함수는 이름 대신 매개 변수를 사용하여 반복 될 수 있습니다! 따라서에 제공된 함수 U에는 함수 (자체)에 바인딩 할 매개 변수가 하나 이상 있어야합니다.

아래 예에서는 종료 조건이 없으므로 스택 오버플로가 발생할 때까지 무한 반복됩니다.

const U = f => f (f) // call function f with itself as an argument

U (f => (console.log ('stack overflow imminent!'), U (f)))

다양한 기술을 사용하여 무한 재귀를 멈출 수 있습니다. 여기에서는 입력을 기다리는 또 다른 익명 함수 를 반환하는 익명 함수를 작성 합니다. 이 경우 일부 숫자입니다. 숫자가 제공 될 때 0보다 크면 계속 반복되고 그렇지 않으면 0을 반환합니다.

const log = x => (console.log (x), x)

const U = f => f (f)

// when our function is applied to itself, we get the inner function back
U (f => x => x > 0 ? U (f) (log (x - 1)) : 0)
// returns: (x => x > 0 ? U (f) (log (x - 1)) : 0)
// where f is a reference to our outer function

// watch when we apply an argument to this function, eg 5
U (f => x => x > 0 ? U (f) (log (x - 1)) : 0) (5)
// 4 3 2 1 0

여기서 즉시 분명하지 않은 것은 우리의 함수가 처음 U결합 자를 사용하여 자신에게 적용될 때 첫 번째 입력을 기다리는 함수를 반환한다는 것입니다. 이것에 이름을 부여하면 람다 (익명 함수)를 사용하여 재귀 함수를 효과적으로 구성 할 수 있습니다.

const log = x => (console.log (x), x)

const U = f => f (f)

const countDown = U (f => x => x > 0 ? U (f) (log (x - 1)) : 0)

countDown (5)
// 4 3 2 1 0

countDown (3)
// 2 1 0

이것은 직접 재귀 가 아닙니다 . 자체 이름을 사용하여 자신을 호출하는 함수입니다. 우리의 정의는 countDown본문 내부를 참조하지 않으며 여전히 재귀가 가능합니다.

// direct recursion references itself by name
const loop = (params) => {
  if (condition)
    return someValue
  else
    // loop references itself to recur...
    return loop (adjustedParams)
}

// U combinator does not need a named reference
// no reference to `countDown` inside countDown's definition
const countDown = U (f => x => x > 0 ? U (f) (log (x - 1)) : 0)

U 결합기를 사용하여 기존 함수에서 자체 참조를 제거하는 방법

여기에서는 자체 참조를 사용하는 재귀 함수를 취하고 자체 참조 대신 U 결합자를 사용하는 함수로 변경하는 방법을 보여줍니다.

const factorial = x =>
  x === 0 ? 1 : x * factorial (x - 1)
  
console.log (factorial (5)) // 120

이제 U 결합자를 사용하여 내부 참조를 factorial

const U = f => f (f)

const factorial = U (f => x =>
  x === 0 ? 1 : x * U (f) (x - 1))

console.log (factorial (5)) // 120

기본 교체 패턴은 이것입니다. 다음 섹션에서 비슷한 전략을 사용할 것입니다.

// self reference recursion
const foo =         x => ...   foo (nextX) ...

// remove self reference with U combinator
const foo = U (f => x => ... U (f) (nextX) ...)

Y 결합 자

관련 : 거울 비유를 사용하여 설명 된 U 및 Y 결합 자

이전 섹션에서는 U 결합자를 사용하여 명명 된 함수에 의존하지 않는 재귀 함수로 자기 참조 재귀를 변환하는 방법을 보았습니다. 항상 함수를 첫 번째 인수로 자신에게 전달하는 것을 기억해야하는 약간의 성가심이 있습니다. 음, Y-combinator는 U-combinator를 기반으로하며 지루한 부분을 제거합니다. 복잡성 제거 / 감소가 우리가 함수를 만드는 주된 이유이기 때문에 이것은 좋은 것입니다.

먼저 우리 고유의 Y- 콤비 네이터를 유도 해 보겠습니다.

// standard definition
const Y = f => f (Y (f))

// prevent immediate infinite recursion in applicative order language (JS)
const Y = f => f (x => Y (f) (x))

// remove reference to self using U combinator
const Y = U (h => f => f (x => U (h) (f) (x)))

이제 U-combinator와 비교하여 사용법을 살펴 보겠습니다. 되풀이하려면 U (f)단순히 호출하는 대신f ()

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

Y (f => (console.log ('stack overflow imminent!'),  f ()))

이제 다음을 countDown사용 하여 프로그램을 시연하겠습니다 Y. 프로그램은 거의 동일하지만 Y 조합기는 좀 더 깔끔하게 유지합니다.

const log = x => (console.log (x), x)

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const countDown = Y (f => x => x > 0 ? f (log (x - 1)) : 0)

countDown (5)
// 4 3 2 1 0

countDown (3)
// 2 1 0

그리고 이제 우리는 또한 볼 factorial것입니다

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const factorial = Y (f => x =>
  x === 0 ? 1 :  x * f (x - 1))

console.log (factorial (5)) // 120

보시다시피 f는 재귀 자체의 메커니즘이됩니다. 되풀이하려면 일반 함수처럼 호출합니다. 다른 인수로 여러 번 호출 할 수 있으며 결과는 여전히 정확합니다. 그것은 일반적인 기능 매개 변수이기 때문에, 우리는 우리가 같은 원하는대로 그 이름을 지정할 수 있습니다 recur아래 -

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const fibonacci = Y (recur => n =>
  n < 2 ? n : recur (n - 1) +  (n - 2))

console.log (fibonacci (10)) // 55


둘 이상의 매개 변수가있는 U 및 Y 결합 자

위의 예에서 우리는 계산의 "상태"를 추적하기 위해 인수를 반복하고 전달할 수있는 방법을 보았습니다. 하지만 추가 상태를 추적해야하는 경우 어떻게해야합니까?

우리는 할 수 배열이나 뭐 같은 화합물 데이터를 사용하여 ...

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const fibonacci = Y (f => ([a, b, x]) =>
  x === 0 ? a : f ([b, a + b, x - 1]))

// starting with 0 and 1, generate the 7th number in the sequence
console.log (fibonacci ([0, 1, 7])) 
// 0 1 1 2 3 5 8 13

그러나 이것은 내부 상태 (카운터 ab)를 노출하기 때문에 나쁩니다 . fibonacci (7)우리가 원하는 답을 얻기 위해 전화 를 걸 수 있다면 좋을 것 입니다.

커리 함수 (단항 (1 매개 변수) 함수의 시퀀스)에 대해 알고있는 것을 Y사용하면 복합 데이터 또는 고급 언어 기능에 대한 정의를 수정 하거나 의존 하지 않고도 목표를 쉽게 달성 할 수 있습니다.

fibonacci아래 의 정의를 자세히 살펴보십시오 . 우리는 즉시 적용 0하고 1있으며 각각 a과 바인딩됩니다 b. 이제 피보나치는에 바인딩 될 마지막 인수가 제공되기를 기다 x립니다. 재귀 할 때는 함수가 카레 형태이기 때문에 f (a) (b) (x)(아님 f (a,b,x))을 호출해야합니다 .

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const fibonacci = Y (f => a => b => x =>
  x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1)

console.log (fibonacci (7)) 
// 0 1 1 2 3 5 8 13


이러한 종류의 패턴은 모든 종류의 함수를 정의하는 데 유용 할 수 있습니다. 우리가 사용하는 정의 된 두 가지 이상의 기능 볼 수 아래 Y콤비 ( rangereduce)과의 유도체 reduce, map.

const U = f => f (f)

const Y = U (h => f => f (x => U (h) (f) (x)))

const range = Y (f => acc => min => max =>
  min > max ? acc : f ([...acc, min]) (min + 1) (max)) ([])

const reduce = Y (f => g => y => ([x,...xs]) =>
  x === undefined ? y : f (g) (g (y) (x)) (xs))
  
const map = f =>
  reduce (ys => x => [...ys, f (x)]) ([])
  
const add = x => y => x + y

const sq = x => x * x

console.log (range (-2) (2))
// [ -2, -1, 0, 1, 2 ]

console.log (reduce (add) (0) ([1,2,3,4]))
// 10

console.log (map (sq) ([1,2,3,4]))
// [ 1, 4, 9, 16 ]


모두 익명의 세상에

여기서는 순수 함수로 작업하기 때문에 이름이 지정된 함수를 정의로 대체 할 수 있습니다. 피보나치를 취하고 명명 된 함수를 표현으로 대체 할 때 어떤 일이 발생하는지보십시오

/* const U = f => f (f)
 *
 * const Y = U (h => f => f (x => U (h) (f) (x)))
 *
 * const fibonacci = Y (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1)
 *
 */

/*
 * given fibonacci (7)
 *
 * replace fibonacci with its definition
 * Y (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
 *
 * replace Y with its definition
 * U (h => f => f (x => U (h) (f) (x))) (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
//
 * replace U with its definition
 * (f => f (f)) U (h => f => f (x => U (h) (f) (x))) (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
 */

let result =
  (f => f (f)) (h => f => f (x => h (h) (f) (x))) (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
  
console.log (result) // 13

그리고 거기에 있습니다 – fibonacci (7)익명 함수만을 사용하여 재귀 적으로 계산됩니다.


14

대신 "익명 객체"를 사용하는 것이 가장 간단 할 수 있습니다.

({
  do: function() {
    console.log("don't run this ...");
    this.do();
  }
}).do();

당신의 글로벌 공간은 완전히 오염되지 않았습니다. 매우 간단합니다. 또한 개체의 비전 역 상태를 쉽게 활용할 수 있습니다.

ES6 객체 메서드를 사용하여 구문을 더 간결하게 만들 수도 있습니다.

({
  do() {
    console.log("don't run this ...");
    this.do();
  }
}).do();

13

나는 이것을 인라인 함수로하지 않을 것이다. 그것은 좋은 맛의 경계를 넘어서고 실제로 아무것도 얻지 못합니다.

정말로 필요하다면 arguments.calleeFabrizio의 대답과 같습니다. 그러나 이것은 일반적으로 바람직하지 않은 것으로 간주되며 ECMAScript Fifth Edition의 '엄격 모드'에서는 허용되지 않습니다. ECMA 3 및 non-strict-mode는 사라지지 않지만 엄격 모드에서 작업하면 더 많은 언어 최적화가 가능합니다.

명명 된 인라인 함수를 사용할 수도 있습니다.

(function foo(data){
    data++;
    var nothing = function() {
        foo(data);
    }
    nothing();
})();

그러나 IE의 JScript가 나쁜 일을하기 때문에 명명 된 인라인 함수 식도 피하는 것이 가장 좋습니다. 위의 예 foo에서 IE의 부모 범위 를 잘못 오염시키고 부모 foofoo내부 에서 본에 대한 별도의 인스턴스 foo입니다.

이것을 인라인 익명 함수에 넣는 목적은 무엇입니까? 부모 범위를 오염시키지 않으려면 물론 다른 자체 호출 익명 함수 (네임 스페이스) 안에 첫 번째 예제를 숨길 수 있습니다. nothing재귀와 관련하여 매번 새 복사본을 만들어야 합니까? 두 개의 단순한 상호 재귀 함수를 포함하는 네임 스페이스를 사용하는 것이 더 나을 수 있습니다.


나는 동의한다, 이름이 지정된 함수가 arguments.callee보다 ecmascript 엄격 모드뿐만 아니라 최적화 문제에도 더 적합합니다. 왜냐하면 각 재귀에서 피 호출자에 대한 참조를 얻어야하기 때문입니다 (그리고 이것은 아마도 실행 속도를 감소시킬 수 있기 때문입니다). )

시적 +1, "pushing against the boundaries of good taste"-(좋아요, 좋은 정보).
Peter Ajtai 2010 년

오염이 정말로 우려된다면 간단한 전 / 후위는 어떨까요? 전역 범위에 있지 않다는 점을 고려하면 (함수가 최상위 수준 인 경우에도 이미 전체 코드를 래핑하는 익명 함수가 있어야 함) 같은 이름 recur_foo이 부모 범위의 함수와 충돌 할 가능성이 매우 낮습니다 (또는 -중고).
gblazex 2010 년

매우 흥미 롭습니다 -jsfiddle.net/hck2A-IE 는 당신이 말한 것처럼이 경우 부모를 오염시킵니다. 그것을 깨닫지 못했습니다.
Peter Ajtai 2010 년

1
@Peter : kangax.github.com/nfe (특히 'JScript 버그')는이 주제에 대해 알고 싶었던 것 이상입니다. 마침내 IE9에서 수정되었습니다 (IE9 표준 모드에서만).
bobince

10
(function(data){
    var recursive = arguments.callee;
    data = data+1;
    var nothing = function() {
        recursive(data)
    }
    nothing();
})();

34
나는이 (기술적으로 정확한) 답변에 투표하는 모든 사람들이 문제를 깨닫기를 바랍니다 arguments.callee: 엄격 모드와 ES5에서는 허용되지 않습니다.
Pointy

부결, arguments.callee와는 ES5에서 더 이상 사용되지 않습니다
제이미로드 리 게스에게

NodeJS에서 작동합니다. ES5가 고정 된 환경에서 예측 가능한 방식으로 작동하는 한 저는 ES5에 대해 덜 신경 쓸 수 없습니다.
Angad

1
이것은 시한 폭탄입니다. 위의 주석에서 알 수 있듯이 "고정"환경이라는 것은 없습니다. 수천 가지 이유 때문에 거의 항상 업그레이드 할 것입니다.
sampathsris

6

다음과 같이 할 수 있습니다.

(foo = function() { foo(); })()

또는 귀하의 경우 :

(recur = function(data){
    data = data+1;
    var nothing = function() {
        if (data > 100) return; // put recursion limit
        recur(data);
    }
    nothing();
})(/* put data init value here */ 0);

선언문으로 recur먼저 선언 할 수 var있습니다. 그것이 질문의 규칙을 어겼는지 여부는 알 수 없지만 지금 가지고있는 것처럼 var문장이 없으면 ECMAScript 5 엄격 모드에서 오류가 발생합니다.
Tim Down

내 초기 의견에는 var키워드가 포함 되었지만이 코드를 테스트 한 후에는 자체 호출 블록 내부에서 변수를 실제로 선언 할 수 없기 때문에 오류가 발생했습니다. 그리고 내 접근 방식은 정의되지 않은 변수의 자동 선언에 의존하므로 @Pointy의 솔루션이 더 정확합니다. 하지만 여전히 Fabrizio Calderan 답변에 투표했습니다.)
ArtBIT

예, (var recur = function() {...})();이제 할당 표현식 (할당 된 값을 반환)이 아닌 명령문이므로 작동하지 않습니다. var recur; (recur = function() {...})();대신 제안 했습니다.
Tim Down

3

다음과 같이 익명 함수를 선언 할 때 :

(function () {
    // Pass
}());

함수 표현식으로 간주되며 선택적 이름 (자체 내에서 호출하는 데 사용할 수 있음)이 있습니다. 그러나 함수 표현식 (문이 아님)이기 때문에 익명으로 유지됩니다 (하지만 호출 할 수있는 이름이 있음). 이 함수는 자신을 호출 할 수 있습니다.

(function foo () {
    foo();
}());
foo //-> undefined

"익명으로 유지됩니다" – 아닙니다. 익명 함수에는 이름이 없습니다. 나는 그것이 foo현재 컨텍스트 내에서 선언되지 않는다는 것을 이해 하지만 다소 관련이 없습니다. 이름이있는 함수는 여전히 익명이 아닌 명명 된 함수 입니다.
감사합니다

3

함수를 functio 자체에 전달하지 않는 이유는 무엇입니까?

    var functionCaller = function(thisCaller, data) {
        data = data + 1;
        var nothing = function() {
            thisCaller(thisCaller, data);
        };
        nothing();
    };
    functionCaller(functionCaller, data);

3

특정 상황에서는 익명 함수에 의존해야합니다. 재귀 map함수 가 주어집니다 .

const map = f => acc => ([head, ...tail]) => head === undefined 
 ? acc
 : map (f) ([...acc, f(head)]) (tail);

const sqr = x => x * x;
const xs = [1,2,3,4,5];

console.log(map(sqr) ([0]) (xs)); // [0] modifies the structure of the array

참고 map배열의 구조를 수정하지해야합니다. 따라서 누산기 acc는 노출 될 필요가 없습니다. map예를 들어 다른 함수로 래핑 할 수 있습니다 .

const map = f => xs => {
  let next = acc => ([head, ...tail]) => head === undefined
   ? acc
   : map ([...acc, f(head)]) (tail);

  return next([])(xs);
}

그러나이 솔루션은 매우 장황합니다. 과소 평가 된 U결합 자를 사용합시다 .

const U = f => f(f);

const map = f => U(h => acc => ([head, ...tail]) => head === undefined 
 ? acc
 : h(h)([...acc, f(head)])(tail))([]);

const sqr = x => x * x;
const xs = [1,2,3,4,5];

console.log(map(sqr) (xs));

간결하지 않습니까? U죽은 간단하지만 재귀 호출이 난독 비트를 얻을 수 있다는 단점이있다 : sum(...)이된다 h(h)(...)- 모든 있다고.


2

대답이 여전히 필요한지 확실하지 않지만 function.bind를 사용하여 만든 대리자를 사용하여 수행 할 수도 있습니다.

    var x = ((function () {
        return this.bind(this, arguments[0])();
    }).bind(function (n) {
        if (n != 1) {
            return n * this.bind(this, (n - 1))();
        }
        else {
            return 1;
        }
    }))(5);

    console.log(x);

여기에는 명명 된 함수 나 인수가 포함되지 않습니다.


1

bobince가 작성한 것처럼 단순히 함수의 이름을 지정하십시오.

그러나 초기 값을 전달하고 결국 함수를 중지하고 싶을 것 같습니다!

var initialValue = ...

(function recurse(data){
    data++;
    var nothing = function() {
        recurse(data);
    }
    if ( ... stop condition ... )
        { ... display result, etc. ... }
    else
        nothing();
}(initialValue));

작업 jsFiddle 예제 (재미를 위해 데이터 + = 데이터 사용)



1
+1, 이것은 매우 유용한 답변이며 더 많은 찬성 투표를 받아야하지만 익명이 아닙니다.
Incognito

당신은 분명히 보 빈스가 쓴 글을 읽지 않았습니다 : However named inline function expressions are also best avoided.. 하지만 OP도 요점을 놓치고 있습니다 ... :)
gblazex

@Galamb-나는 그것을 읽었다. 엄격 모드 및 ES5에서 허용되지 않는 것은 상위 범위를 오염시키고 추가 인스턴스를 만드는 것과 동일하지 않습니다.
Peter Ajtai 2010 년

1

나는 문자열을 구성하는 객체를 따라가는 한 줄 익명 함수가 필요했습니다 (또는 원했습니다).

var cmTitle = 'Root' + (function cmCatRecurse(cmCat){return (cmCat == root) ? '' : cmCatRecurse(cmCat.parent) + ' : ' + cmCat.getDisplayName();})(cmCurrentCat);

'Root : foo : bar : baz : ...'와 같은 문자열을 생성합니다.


1

ES2015를 사용하면 구문을 약간 다루고 기본 매개 변수와 썽크를 남용 할 수 있습니다. 후자는 인수가없는 함수일뿐입니다.

const applyT = thunk => thunk();

const fib = n => applyT(
  (f = (x, y, n) => n === 0 ? x : f(y, x + y, n - 1)) => f(0, 1, n)
);

console.log(fib(10)); // 55

// Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55...

주의하시기 바랍니다 f익명 함수와 매개 변수 (x, y, n) => n === 0 ? x : f(y, x + y, n - 1)의 디폴트 값으로. 때 f호출되는 applyT기본값이 사용되도록, 인수없이 이루어져야한다이 호출. 기본값은 함수이므로 f자신을 재귀 적으로 호출 할 수있는 명명 된 함수입니다.


0

명명 된 함수 또는 인수를 포함하지 않는 또 다른 답변입니다.

var sum = (function(foo,n){
  return n + foo(foo,n-1);
})(function(foo,n){
     if(n>1){
         return n + foo(foo,n-1)
     }else{
         return n;
     }
},5); //function takes two argument one is function and another is 5

console.log(sum) //output : 15

nice : 익명 함수를 로컬 매개 변수에 바인드 한 다음 로컬 매개 변수를 통해 함수를 호출하지만 재귀를 위해 함수를 자신에게 전달합니다.
englebart

0

이것은 다른 이름과 약간 수정 된 항목으로 jforjs 답변의 재 작업입니다.

// function takes two argument: first is recursive function and second is input
var sum = (function(capturedRecurser,n){
  return capturedRecurser(capturedRecurser, n);
})(function(thisFunction,n){
     if(n>1){
         return n + thisFunction(thisFunction,n-1)
     }else{
         return n;
     }
},5); 

console.log(sum) //output : 15

첫 번째 재귀를 풀 필요가 없었습니다. 참조로서 자신을 수신하는 함수는 OOP의 원시적 인 오물을 다시 불러옵니다.


0

이것은 화살표 기능이있는 @zem의 답변 버전입니다.

U또는 Y조합자를 사용할 수 있습니다 . Y 결합자는 사용하기 가장 간단합니다.

U combinator, 이것으로 함수를 계속 전달해야합니다. const U = f => f(f) U(selfFn => arg => selfFn(selfFn)('to infinity and beyond'))

Y combinator를 사용하면 함수를 계속 전달할 필요가 없습니다. const Y = gen => U(f => gen((...args) => f(f)(...args))) Y(selfFn => arg => selfFn('to infinity and beyond'))


0

rosetta-code 링크를 사용하는 또 다른 Y-combinator 솔루션 (누군가 이전에 stackOverflow 어딘가에 링크를 언급했다고 생각합니다.

화살표는 나에게 더 읽기 쉬운 익명 함수를위한 것입니다.

var Y = f => (x => x(x))(y => f(x => y(y)(x)));

-1

이것은 모든 곳에서 작동하지 않을 수 있지만 arguments.callee현재 기능을 참조하는 데 사용할 수 있습니다 .

따라서 팩토리얼은 다음과 같이 수행 될 수 있습니다.

var fac = function(x) { 
    if (x == 1) return x;
    else return x * arguments.callee(x-1);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.