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.