[javascript] 재귀 적으로 자바 스크립트 함수 호출
다음과 같이 변수에 재귀 함수를 만들 수 있습니다.
/* Count down to 0 recursively.
*/
var functionHolder = function (counter) {
output(counter);
if (counter > 0) {
functionHolder(counter-1);
}
}
이와 함께, functionHolder(3);
출력 할 것이다 3
2
1
0
. 다음을 수행했다고 가정 해 보겠습니다.
var copyFunction = functionHolder;
copyFunction(3);
3
2
1
0
위와 같이 출력 됩니다. 그런 functionHolder
다음 다음과 같이 변경 하면 :
functionHolder = function(whatever) {
output("Stop counting!");
그런 functionHolder(3);
줄 것 Stop counting!
예상대로.
copyFunction(3);
이제는 (자체가 가리키는) 함수가 아니라 3
Stop counting!
참조하는대로 제공합니다 functionHolder
. 이것은 어떤 상황에서는 바람직 할 수 있지만 함수를 보유하는 변수가 아닌 자체 호출하도록 함수를 작성하는 방법이 있습니까?
즉, 전화를 걸 때이 모든 단계를 거치면서 여전히 제공되도록 회선 만 변경할 수 있습니까? 시도 했지만 오류가 발생 합니다.functionHolder(counter-1);
3
2
1
0
copyFunction(3);
this(counter-1);
this is not a function
답변
명명 된 함수 표현식 사용 :
함수 표현식에 실제로 비공개 이름을 지정할 수 있으며 자체적으로 만 함수 내부에서 볼 수 있습니다.
var factorial = function myself (n) {
if (n <= 1) {
return 1;
}
return n * myself(n-1);
}
typeof myself === 'undefined'
여기서 myself
인 함수의 표시 만 내부 자체.
이 개인 이름을 사용하여 함수를 재귀 적으로 호출 할 수 있습니다.
13. Function Definition
ECMAScript 5 사양을 참조하십시오 .
FunctionExpression의 식별자는 FunctionExpression의 FunctionBody 내부에서 참조되어 함수가 자신을 재귀 적으로 호출 할 수 있습니다. 그러나 FunctionDeclaration과 달리 FunctionExpression의 식별자는 FunctionExpression을 포함하는 범위에서 참조 될 수 없으며 영향을주지 않습니다.
Internet Explorer 버전 8까지의 이름은 실제로 둘러싼 변수 환경에서 볼 수 있기 때문에 올바르게 작동하지 않으며 실제 함수의 복제본을 참조합니다 (아래 patrick dw 의 주석 참조).
arguments.callee 사용 :
또는 arguments.callee
현재 함수를 참조하는 데 사용할 수 있습니다 .
var factorial = function (n) {
if (n <= 1) {
return 1;
}
return n * arguments.callee(n-1);
}
ECMAScript 5 판은 엄격 모드 에서 arguments.callee () 사용을 금지 합니다. 하지만 다음과 같습니다.
(From MDN ) : 일반 코드에서 arguments.callee는 둘러싸는 함수를 나타냅니다. 이 사용 사례는 약합니다. 단순히 둘러싸는 함수의 이름을 지정하십시오! 또한 arguments.callee에 액세스하면 인라인되지 않은 함수에 대한 참조를 제공 할 수 있어야하기 때문에 arguments.callee는 인라인 함수와 같은 최적화를 실질적으로 방해합니다. 엄격 모드 함수에 대한 arguments.callee는 설정 또는 검색 할 때 throw되는 삭제 불가능한 속성입니다.
답변
arguments.callee
[MDN]을 사용하여 기능 자체에 액세스 할 수 있습니다 .
if (counter>0) {
arguments.callee(counter-1);
}
그러나 엄격 모드에서는 중단됩니다.
답변
Y-combinator를 사용할 수 있습니다 : ( Wikipedia )
// ES5 syntax
var Y = function Y(a) {
return (function (a) {
return a(a);
})(function (b) {
return a(function (a) {
return b(b)(a);
});
});
};
// ES6 syntax
const Y = a=>(a=>a(a))(b=>a(a=>b(b)(a)));
// If the function accepts more than one parameter:
const Y = a=>(a=>a(a))(b=>a((...a)=>b(b)(...a)));
그리고 다음과 같이 사용할 수 있습니다.
// ES5
var fn = Y(function(fn) {
return function(counter) {
console.log(counter);
if (counter > 0) {
fn(counter - 1);
}
}
});
// ES6
const fn = Y(fn => counter => {
console.log(counter);
if (counter > 0) {
fn(counter - 1);
}
});
답변
나는 이것이 오래된 질문이라는 것을 알고 있지만 명명 된 함수 표현식을 사용하지 않으려면 사용할 수있는 솔루션을 하나 더 제시하겠다고 생각했습니다. (피해야하거나 피해서는 안된다고 말하는 것이 아니라 다른 해결책을 제시하는 것뿐입니다)
var fn = (function() {
var innerFn = function(counter) {
console.log(counter);
if(counter > 0) {
innerFn(counter-1);
}
};
return innerFn;
})();
console.log("running fn");
fn(3);
var copyFn = fn;
console.log("running copyFn");
copyFn(3);
fn = function() { console.log("done"); };
console.log("fn after reassignment");
fn(3);
console.log("copyFn after reassignment of fn");
copyFn(3);
답변
다음은 매우 간단한 예입니다.
var counter = 0;
function getSlug(tokens) {
var slug = '';
if (!!tokens.length) {
slug = tokens.shift();
slug = slug.toLowerCase();
slug += getSlug(tokens);
counter += 1;
console.log('THE SLUG ELEMENT IS: %s, counter is: %s', slug, counter);
}
return slug;
}
var mySlug = getSlug(['This', 'Is', 'My', 'Slug']);
console.log('THE SLUG IS: %s', mySlug);
공지 사항 그 counter
무엇에 관해서 카운트 “뒤로” slug
의 값입니다. 함수로이 때문에 우리는이 값을 기록하는되는 위치이다 재발 그래서, 우리는 본질적으로 점점 더 깊이 중첩 유지 – 로그인하기 전에이 호출 스택 전에 로깅이 일어난다.
재귀가 최종 호출 스택 항목을 충족하면 함수 호출을 “밖으로” 트램 폴링 하는 반면, 첫 번째 증가 counter
는 마지막 중첩 호출 내부에서 발생합니다.
나는 이것이 질문자 코드의 “수정”이 아니라는 것을 알고 있지만 일반적으로 예시 할 것이라고 생각한 제목을 감안할 때 재귀 에 대한 더 나은 이해를 위해 재귀 를 .