arguments.callee.caller 속성이 JavaScript에서 더 이상 사용되지 않는 이유는 무엇입니까?


214

arguments.callee.callerJavaScript 에서 속성이 더 이상 사용되지 않는 이유는 무엇 입니까?

JavaScript에서 추가 된 후 더 이상 사용되지 않지만 ECMAScript에서는 완전히 생략되었습니다. 일부 브라우저 (Mozilla, IE)는 항상 해당 브라우저를 지원했으며 지원을 제거 할 계획이 없습니다. 다른 사람들 (Safari, Opera)은 이에 대한 지원을 채택했지만 이전 브라우저에서의 지원은 신뢰할 수 없습니다.

이 귀중한 기능을 림보에 넣을만한 충분한 이유가 있습니까?

(또는 대안으로, 호출 기능을 처리하는 더 좋은 방법이 있습니까?)


2
널리 사용되는 기능을 가진 기능은 다른 브라우저의 호환성 버그가되기 때문에 다른 브라우저에서 지원됩니다. 사이트가 한 브라우저에만 존재하는 기능을 사용하는 경우 다른 모든 사이트에서는 사이트가 손상되며 일반적으로 사용자는 해당 사이트가 고장난 브라우저라고 생각합니다.
olliej

4
(거의 모든 브라우저가 한 번에 한 번 또는 여러 번이 작업을 수행했습니다. 예를 들어이 기능 (및 JS 자체)은 Netscape, IE에서 시작한 XHR, Safari의 Canvas 등에서 제공됩니다. 이들 중 일부는 유용하며 다른 브라우저에서 선택합니다. 시간이 지남에 따라 (js, canvas, xhr은 모두 예), 일부 (.callee)는 그렇지 않습니다
olliej

@olliej 표준이기 때문에 (혹은 표준에서 사용되지 않더라도) 사용되기 때문에 지원하는 것에 대한 당신의 의견은 매우 사실입니다! 그렇기 때문에 도움이되지 않을 때마다 표준을 무시하기 시작했습니다. 우리는 개발자로서 사양에 따라해야 할 것이 아니라 작동하는 것을 사용하여 표준의 방향을 결정할 수 있습니다. 이것은 우리가 가지고 어떻게 <b>하고 <i>(예, 사람들은 한 지점에서 사용되지 않는) 다시.
Stijn de Witt

답변:


252

JavaScript의 초기 버전에서는 명명 된 함수 표현식이 허용되지 않았기 때문에 재귀 함수 표현식을 작성할 수 없었습니다.

 // This snippet will work:
 function factorial(n) {
     return (!(n>1))? 1 : factorial(n-1)*n;
 }
 [1,2,3,4,5].map(factorial);


 // But this snippet will not:
 [1,2,3,4,5].map(function(n) {
     return (!(n>1))? 1 : /* what goes here? */ (n-1)*n;
 });

이 문제를 해결하기 위해 arguments.callee추가되었습니다.

 [1,2,3,4,5].map(function(n) {
     return (!(n>1))? 1 : arguments.callee(n-1)*n;
 });

그러나 이것은 실제로 다른 해결책, 수신자 및 발신자 문제와 관련하여 일반적인 경우에는 인라인 및 꼬리 재귀를 불가능하게하므로 실제로는 나쁜 해결책이었습니다 (추적 등을 통해 특정 경우에 달성 할 수는 있지만 최상의 코드조차도 가능합니다) 그렇지 않으면 필요하지 않은 점검으로 인해 최적이 아님). 다른 주요 문제는 재귀 호출이 다른 this값 을 얻는다는 것 입니다. 예를 들면 다음과 같습니다.

var global = this;
var sillyFunction = function (recursed) {
    if (!recursed)
        return arguments.callee(true);
    if (this !== global)
        alert("This is: " + this);
    else
        alert("This is the global");
}
sillyFunction();

어쨌든 EcmaScript 3는 다음과 같은 명명 된 함수 표현식을 허용하여 이러한 문제를 해결했습니다.

 [1,2,3,4,5].map(function factorial(n) {
     return (!(n>1))? 1 : factorial(n-1)*n;
 });

이것은 많은 이점이 있습니다 :

  • 함수는 코드 내부에서 다른 것과 같이 호출 할 수 있습니다.

  • 네임 스페이스를 오염시키지 않습니다.

  • 값은 this변경되지 않습니다.

  • 성능이 뛰어납니다 ( arguments 객체에 액세스하는 것이 비쌉니다).

으악,

그 질문은 다른 모든 것에 더해 arguments.callee.caller또는 더 구체적 이라는 것을 깨달았습니다 Function.caller.

어느 시점에서나 스택에서 함수의 가장 깊은 호출자를 찾을 수 있으며 위에서 언급했듯이 호출 스택을 보는 데는 하나의 주요 효과가 있습니다.

예 : 함수 f가 알 수없는 함수를 호출하지 않을 것이라고 보장 할 수 없으면 인라인 할 수 없습니다 f. 기본적으로 그것은 사소하게 불쾌했을 수있는 모든 호출 사이트에 많은 수의 경비원이 축적됨을 의미합니다.

 function f(a, b, c, d, e) { return a ? b * c : d * e; }

js 인터프리터가 제공된 모든 인수가 호출 시점의 숫자임을 보장 할 수 없으면 인라인 코드 앞에 모든 인수에 대한 검사를 삽입하거나 함수를 인라인 할 수 없습니다.

이제이 특별한 경우에, 스마트 통역사는보다 최적의 수표를 재 배열하고 사용할 수없는 값을 검사하지 않을 수 있어야합니다. 그러나 많은 경우에 그것은 가능하지 않으므로 인라인하는 것이 불가능합니다.


12
최적화하기가 어렵다는 이유로 사용이 중단되었다고 말씀하십니까? 어리석은 일입니다.
Thomas Eding

11
아니요, 나는 여러 가지 이유를 나열했습니다. 최적화를 어렵게 만드는 것 외에도 (일반적으로 역사상 최적화하기 어려운
것들도

17
인수는 그 값이 중요한 경우 호출에 의해 설정 될 수있다, 조금 가짜입니다. 일반적으로 사용되지 않습니다 (적어도 재귀 함수에서는 문제가 없었습니다). 이름으로 함수를 호출하면 동일한 문제가 발생 this하므로 수신자 가 좋은지 나쁜지 와 관련이 없다고 생각합니다 . 또한 수신자발신자 는 엄격 모드에서만 "더 이상 사용되지 않습니다"(ECMAscript ed 5, 2009 년 12 월), olliej가 게시 한 2008 년에는 알려지지 않은 것 같습니다.
RobG

8
여전히 논리가 보이지 않습니다. 일급 함수가있는 모든 언어에서 i를 알 필요없이 자신을 참조 할 수있는 함수 본문을 정의 할 수 있다는 점에서 분명한 가치가 있습니다.
Mark Reed

8
RobG가 이것을 지적했지만 그게 전부라고 생각하지는 않습니다. 명명 된 함수를 사용하여 반복 하면 전역 범위 인 this경우 의 값만 보존 this됩니다. 다른 모든 경우 에는 첫 번째 재귀 호출 후 값 this 변경되므로 보존을 this주장 하는 귀하의 답변 부분이 실제로 유효하지 않다고 생각합니다.
JLRishe

89

arguments.callee.caller있다 없다 가의 메이크업을 사용하지 불구하고 사용되지 않는 속성을. ( 현재 기능에 대한 참조를 제공합니다)Function.callerarguments.callee

  • Function.callerECMA3에 따르면 비표준이지만 현재 모든 주요 브라우저에서 구현 됩니다.
  • arguments.caller 더 이상 사용되지 않으며 일부 현재 주요 브라우저 (예 : Firefox 3)에서는 구현되지 않습니다.Function.caller

따라서 상황이 이상적이지는 않지만 모든 주요 브라우저에서 Javascript로 호출 함수에 액세스하려는 경우 이름 지정된 함수 참조에서 직접 액세스하거나 특성을 통해 익명 함수 내에서 특성을 사용할 수 있습니다.Function.callerarguments.callee


5
이것은 더 이상 사용되지 않으며 사용되지 않는 것에 대한 가장 좋은 설명입니다. 매우 유용합니다. Function.caller가 할 수없는 것에 대한 좋은 예를 보려면 (재귀 함수의 스택 추적을 가져 오십시오) developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
Juan Mendes

1
그러나 arguments.callee엄격 모드에서는 금지되어 있습니다. 너무 슬퍼했지만 더 이상 사용하지 않는 것이 좋습니다.
Gras Double

1
MDN에 대한 arguments.callee 하이퍼 링크는 엄격 모드에서 제거되었다고 말합니다. 더 이상 사용되지 않습니까?
styfle

1
참고 arguments.callee.callerES5 엄격 모드에서 더 이상 사용되지 않습니다 "이었다 arguments.callee.caller, 또는 더 구체적으로 Function.caller를 사용되지 않습니다 또 다른 특징." ( 출처 )
thdoan

29

arguments.callee보다 명명 된 함수 를 사용하는 것이 좋습니다 .

 function foo () {
     ... foo() ...
 }

~보다 낫다

 function () {
     ... arguments.callee() ...
 }

명명 된 함수는 호출자 속성을 통해 호출자에게 액세스 할 수 있습니다.

 function foo () {
     alert(foo.caller);
 }

어느 것보다 낫다

 function foo () {
     alert(arguments.callee.caller);
 }

더 이상 사용되지 않는 것은 현재 ECMAScript 설계 원칙 때문 입니다.


2
명명 된 함수를 사용하는 것이 더 좋은 이유를 설명 할 수 있습니까? 익명 함수에서 수신자를 사용할 필요가 없습니까?
AnthonyWJones

27
익명 함수에서 수신자를 사용하는 경우 익명이 아니어야하는 기능이 있습니다.
Prestaul

3
때로는 디버깅하는 가장 쉬운 방법은 .caller ()를 사용하는 것입니다. 이러한 경우 명명 된 함수는 도움이되지 않습니다. 어떤 함수가 호출을 수행하는지 알아 내려고합니다.
SamGoody

6
더 잘 정의하십시오. 예를 들어, IE6-8 arguments.callee가 작동하는 동안 함수 quirks 라고 명명했습니다 .
cmc

1
IE6-8 단점 외에도 코드가 밀접하게 결합됩니다. 객체 및 / 또는 함수의 이름이 하드 코딩 된 경우, ardsasd 및 rsk82에서 언급했듯이 주요 리팩토링 위험이 있으며 코드베이스 크기가 증가함에 따라 증가합니다. 단위 테스트는 방어선으로 사용되지만이 하드 코딩 문제에 대해 개인적으로 만족하는 답은 아닙니다.
Jasmine Hegman

0

확장명입니다. "this"의 값은 재귀 중에 변경됩니다. 다음 (수정 된) 예에서 factorial은 {foo : true} 객체를 가져옵니다.

[1,2,3,4,5].map(function factorial(n) {
  console.log(this);
  return (!(n>1))? 1 : factorial(n-1)*n;
},     {foo:true}     );

처음 호출 된 계승은 객체를 가져 오지만 재귀 호출에는 해당되지 않습니다.


1
당신이 잘못하고 있기 때문에. this유지 관리 해야하는 경우 factorial.call(this, n-1)실제로 재귀 적 코드 작성에서 찾은 것으로 나타났습니다. 일반적으로는 없음 this또는 this트리의 일부 노드를 참조하며 실제로 변경하는 것이 좋습니다.
Stijn de Witt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.