괄호없이 함수 호출


275

오늘은 괄호없이 함수를 호출 할 수 있다고 들었습니다. 내가 생각할 수있는 유일한 방법은 apply또는 과 같은 기능을 사용하는 것 call입니다.

f.apply(this);
f.call(this);

그러나 이들에 괄호를 필요로 apply하고 call원점에서 우리를 떠나. 또한 함수를 setTimeout다음 과 같은 일종의 이벤트 핸들러에 전달하는 아이디어를 고려했습니다 .

setTimeout(f, 500);

그러나 질문은 " setTimeout괄호없이 어떻게 호출 합니까?"가됩니다.

이 수수께끼의 해결책은 무엇입니까? 괄호를 사용하지 않고 Javascript에서 함수를 어떻게 호출 할 수 있습니까?


59
무례하지 않으려 고 노력해야하지만 나는 왜 물어야합니까?
jehna1

36
@ jehna1 함수가 어떻게 호출되는지에 대한 질문에 답 하고 마지막에 괄호가 필요하다고 말했을 때 수정되었습니다.
Mike Cluck

3
놀랄 만한! 그 많은 견인을했을이 질문은 .. 아마도 내가 :-) 그것을 자신을 물어 봤어야 상상하지 않았다
아 미트

5
이것은 내 마음을 아프게하는 일종의 질문입니다. 그러한 학대와 착취를 통해 무엇이 좋을 수 있습니까? <insert any solution>보다 객관적으로 낫거나 더 유용한 하나의 유효한 사용 사례를 알고 싶습니다 f().
감사합니다

5
@Aaron : 올바른 이유는 없지만 Alexander O'Mara의 답변에서 지적했듯이 대괄호를 제거하는 것이 코드 실행을 방지하기에 충분한 지 또는 모호한 Javascript 경쟁은 어떻습니까? 물론 유지 관리 가능한 코드를 작성하려고 할 때 터무니없는 목표이지만 재미있는 질문입니다.
PJTraill

답변:


429

괄호없이 함수를 호출하는 방법에는 여러 가지가 있습니다.

이 함수를 정의했다고 가정 해 봅시다.

function greet() {
    console.log('hello');
}

그런 다음 greet괄호없이 호출하는 몇 가지 방법을 따르십시오 .

1. 생성자로서

함께 new사용하면 함수를 괄호없이 호출 할 수 있습니다 :

new greet; // parentheses are optional in this construct.

에서 온 MDN newoprator :

통사론

new constructor[([arguments])]

2. 그대로 toString또는 valueOf구현

toString그리고 valueOf특별한 방법은 다음과 같습니다 변환이 필요한 경우가 암시 적으로 호출되는 :

var obj = {
    toString: function() {
         return 'hello';
    }
}

'' + obj; // concatenation forces cast to string and call to toString.

이 패턴을 사용하여 greet괄호없이 호출 할 수 있습니다.

'' + { toString: greet };

또는과 valueOf:

+{ valueOf: greet };

valueOf그리고 toString실제로에서 호출 @@ toPrimitive (ES6부터) 방법, 그래서 당신은 또한 구현할 수 있습니다 방법을 :

+{ [Symbol.toPrimitive]: greet }
"" + { [Symbol.toPrimitive]: greet }

2.b valueOf함수 프로토 타입에서 재정의

프로토 타입 에서 valueOf메소드 를 대체하기 위해 이전 아이디어를 취할 수 있습니다 .Function

Function.prototype.valueOf = function() {
    this.call(this);
    // Optional improvement: avoid `NaN` issues when used in expressions.
    return 0; 
};

일단 그렇게하면 다음과 같이 쓸 수 있습니다.

+greet;

그리고 줄 아래에 괄호가 있지만 실제 트리거 호출에는 괄호가 없습니다. "실제로 호출하지 않고 JavaScript에서 메소드 호출" 블로그에서 이에 대해 자세히 알아보십시오.

3. 발전기로

iterator 를 반환하는 생성기 함수 (로 *)를 정의 할 수 있습니다. 스프레드 구문 이나 구문을 사용하여 호출 할 수 있습니다 .for...of

먼저 원래 greet함수 의 생성기 변형이 필요 합니다.

function* greet_gen() {
    console.log('hello');
}

그리고 @@ iterator 메소드를 정의하여 괄호없이 호출합니다 .

[...{ [Symbol.iterator]: greet_gen }];

일반적으로 생성기는 yield어딘가에 키워드를 갖지만 함수를 호출 할 필요는 없습니다.

마지막 문장은 함수를 호출하지만, 그것은 파괴로 도 가능합니다 :

[,] = { [Symbol.iterator]: greet_gen };

또는 for ... of구문이지만 자체 괄호가 있습니다.

for ({} of { [Symbol.iterator]: greet_gen });

원래 기능을 사용하여 위의 작업을 수행 할 수도greet 있지만 실행 greet (FF 및 Chrome에서 테스트 된) 프로세스에서 예외가 발생합니다 . try...catch블록으로 예외를 관리 할 수 있습니다.

4. 게터로서

@ jehna1은 이것에 대한 완전한 답을 가지고 있으므로 그에게 신용을주십시오. 다음은 사용되지 않는 메소드를 피하면서 전역 범위에서 괄호 없이 함수를 호출하는 방법입니다. 대신 사용 합니다.__defineGetter__Object.defineProperty

이를 위해 원래 greet함수 의 변형을 작성해야합니다 .

Object.defineProperty(window, 'greet_get', { get: greet });

그리고:

greet_get;

교체 window글로벌 객체가 무엇이든 함께.

다음 greet과 같이 전역 객체에 흔적을 남기지 않고 원래 함수를 호출 할 수 있습니다 .

Object.defineProperty({}, 'greet', { get: greet }).greet;

그러나 우리는 여기에 괄호가 있다고 주장 할 수 있습니다 (실제 호출에 관여하지는 않지만).

5. 태그 기능

ES6부터 다음 구문 으로 템플릿 리터럴 을 전달하는 함수를 호출 할 수 있습니다 .

greet``;

"태그 된 템플릿 리터럴"을 참조하십시오 .

6. 프록시 처리기

ES6부터 프록시를 정의 할 수 있습니다 .

var proxy = new Proxy({}, { get: greet } );

그런 다음 속성 값을 읽으면 다음이 호출됩니다 greet.

proxy._; // even if property not defined, it still triggers greet

이것에는 많은 변형이 있습니다. 하나 더 예 :

var proxy = new Proxy({}, { has: greet } );

1 in proxy; // triggers greet

7. 인스턴스 검사기

instanceof연산자는 실행 @@hasInstance정의 할 때 두 번째 오퍼랜드에 대한 방법 :

1 instanceof { [Symbol.hasInstance]: greet } // triggers greet

1
를 사용하는 매우 흥미로운 접근 방식 valueOf입니다.
Mike Cluck

4
ES6를 잊어 버렸습니다 :func``;
Ismael Miguel

1
eval :)을 호출하여 괄호를 사용했습니다.
trincot

1
이 경우 함수는 실행되지 않지만 호출자에게 전달됩니다.
trincot

1
@trincot 또 다른 방법은 파이프 라인 연산자로 곧 가능할 것입니다 .'1' |> alert
deniro

224

가장 쉬운 방법은 new연산자를 사용하는 것 입니다.

function f() {
  alert('hello');
}

new f;

그것은 정통적이고 부자연 스럽지만 작동하며 완벽하게 합법적입니다.

new매개 변수를 사용하지 않을 경우 운영자는 괄호를 필요로하지 않습니다.


6
수정을 수행하는 가장 쉬운 방법은 함수 표현식을 강제로 평가하는 피연산자를 추가하는 것입니다. !f생성자 함수의 인스턴스를 인스턴스화하지 않고 동일한 결과를 얻습니다 (이 컨텍스트를 새로 작성해야 함). 훨씬 성능이 뛰어나며 많은 인기있는 라이브러리 (예 : Bootstrap)에서 사용됩니다.
THEtheChad

6
@THEtheChad-표현식을 평가하는 것은 함수를 실행하는 것과 같지 않지만 함수를 호출하는 (실행을 유발하는) 다른 (더 똑똑한가? 더 놀라운가) 방법이 있다면 답을 게시하십시오!
Amit

느낌표, 또는 다른 어떤 단일 문자 단항 연산자 (앞에 추가의 포인트 +, -, ~등의 라이브러리)의 반환 값이 필요하지 않은 라이브러리의 최소화 버전에서 바이트를 저장하는 것입니다. (예 !function(){}()) 평소 자기 호출하는 구문은 (function(){})()(불행하게도 구문이 function(){}()크로스 브라우저되지 않습니다) 맨 위에있는자가 호출 기능은 일반적으로 반환 아무 상관이 없기 때문에, 그것은 일반적으로이 바이트 저장 기술의 목표이다
Ultimater

1
@THEtheChad 이것이 사실입니까? 방금 Chrome에서 시도했지만 기능이 실행되지 않았습니다. function foo() { alert("Foo!") };예를 들면 : !foo리턴false
글렌 'devalias 명'

95

게터와 세터를 사용할 수 있습니다.

var h = {
  get ello () {
    alert("World");
  }
}

다음을 사용하여이 스크립트를 실행하십시오.

h.ello  // Fires up alert "world"

편집하다:

우리는 심지어 논쟁을 할 수 있습니다!

var h = {
  set ello (what) {
    alert("Hello " + what);
  }
}

h.ello = "world" // Fires up alert "Hello world"

편집 2 :

괄호없이 실행할 수있는 전역 함수를 정의 할 수도 있습니다.

window.__defineGetter__("hello", function() { alert("world"); });
hello;  // Fires up alert "world"

그리고 논쟁과 함께 :

window.__defineSetter__("hello", function(what) { alert("Hello " + what); });
hello = "world";  // Fires up alert "Hello world"

부인 성명:

@MonkeyZeus가 말했듯이 : 의도가 아무리 좋더라도 프로덕션 에서이 코드를 절대 사용하지 마십시오.


9
POV로부터 엄밀히 말하면, "나는 더 크고 더 나은 것들로 넘어 갔기 때문에 당신의 코드를 인계받는 영광을 가진 도끼 휘두르는 미친 사람입니다. 나는 이것이 정상적인 롤이 아니기를 바랍니다. 유지 관리하는 플러그인 내부에서 사용 가능. 비즈니스 논리 코드 작성, 도끼를 선명하게하는 동안 기다려주세요. :)
MonkeyZeus

3
@MonkeyZeus haha, 그렇습니다! Google에서이를 찾을 수있는 미래의 코더에 대한 면책 ​​조항을 추가했습니다.
jehna1

실제로이 면책 조항은 너무 가혹합니다. "getter as a function call"에 대한 합법적 인 사용 사례가 있습니다. 실제로 매우 성공적인 라이브러리에서 광범위하게 사용됩니다. (당신은 힌트를 싶습니다 ?? :-)
아 미트

1
참고 __defineGetter__되지 않습니다. Object.defineProperty대신 사용하십시오 .
Felix Kling

2
@MonkeyZeus- 명시 적으로 주석에 작성한 이 스타일의 함수 호출 내부적으로가 아니라 API 자체로서 매우 성공적인 공용 라이브러리에서 광범위하고 의도적 으로 사용됩니다 .
Amit

23

특정 상황에 대한 는 다음과 같습니다 .

window.onload = funcRef;

비록 그 진술이 실제로 발동되는 것은 아니지만 미래의 발발로 이어질 것입니다 입니다.

그러나, 나는 회색 지역이 다음과 같은 수수께끼에 대해 괜찮을 것이라고 생각합니다.


6
훌륭하지만 JavaScript는 아닙니다. DOM입니다.
Amit

6
@Amit, DOM은 브라우저의 JS 환경의 일부이며 여전히 JavaScript입니다.
zzzzBov

3
@zzzzBov 모든 ECMAScript가 웹 브라우저에서 실행되는 것은 아닙니다. 또는 Node와 달리 "JavaScript"를 사용하여 ES를 HTML DOM과 결합하는 것을 구체적으로 언급하는 사람들이 있습니까?
Damian Yerrick

9
@DamianYerrick, DOM을 일부 JS 환경에서 사용 가능한 라이브러리로 간주하므로 일부 환경에서 사용 가능한 밑줄보다 JavaScript가 적지 않습니다. 여전히 JavaScript이며 ECMAScript 사양에서 지정된 부분이 아닙니다.
zzzzBov

3
@zzzzBov, "DOM은 종종 JavaScript를 사용하여 액세스하지만 JavaScript의 일부가 아닙니다. 다른 언어로도 액세스 할 수 있습니다." . 예를 들어 FireFox는 DOM 구현에 XPIDL 및 XPCOM을 사용합니다. 지정된 콜백 함수의 호출이 JavaScript로 구현되는 것은 자명하지 않습니다. DOM은 다른 JavaScript 라이브러리와 같은 API가 아닙니다.
trincot

17

측면 사고 방식을 받아들이면 브라우저에는 실제 괄호 문자없이 함수 호출을 포함하여 임의의 JavaScript를 실행하기 위해 남용 할 수있는 몇 가지 API가 있습니다.

1. location 그리고javascript: 프로토콜 :

그러한 기술 중 하나는 javascript:location 할당시 프로토콜 입니다.

작업 예 :

location='javascript:alert\x281\x29'

코드가 일단 평가되면 기술적 \x28 으로 \x29는 여전히 괄호 이지만 실제 () 문자는 나타나지 않습니다. 괄호는 할당시 평가되는 JavaScript 문자열로 이스케이프됩니다.


2. onerroreval:

마찬가지로 브라우저에 따라 전역 onerror을로 설정하고 eval유효한 JavaScript로 묶을 무언가를 던져서 남용 할 수 있습니다 . 브라우저는이 동작에 일관성이 없기 때문에 까다 롭지 만 Chrome의 예입니다.

Chrome의 실제 예 (Firefox가 아닌 다른 테스트되지 않은) :

window.onerror=eval;Uncaught=0;throw';alert\x281\x29';

이것은 거의 유효한 JavaScript 인에 대한 첫 번째 인수로 throw'test'전달 되기 때문에 Chrome에서 작동 합니다. 우리가 대신 하면 통과합니다'Uncaught test'onerrorthrow';test''Uncaught ;test' 합니다. 이제 유효한 JavaScript가 있습니다! 그냥 정의 Uncaught하고 테스트를 페이로드로 바꾸십시오.


결론적으로:

이러한 코드는 정말 끔찍한 , 그리고 사용해서는 안됩니다 이야기의 도덕적 않도록 방지 XSS에 괄호를 필터링에 의존하지 않는 것입니다,하지만 때로는 XSS 공격에 사용됩니다. 이러한 코드를 방지하기 위해 CSP 를 사용하는 것도 좋은 생각입니다.


eval실제로 괄호 문자를 사용하지 않고 문자열 을 사용 하고 쓰는 것과 동일하지 않습니까?
Zev Spitz

@ZenSpitz Yep이지만 eval일반적으로 괄호가 필요 하므로이 필터 회피 해킹입니다.
Alexander O'Mara

5
틀림없이 \x28하고 \x29여전히 괄호입니다. '\x28' === '('.
trincot

@trincot 대답에서 다룬 점의 일종 인 이것은 측면 사고 방식으로 이것이 수행 될 수있는 이유를 보여줍니다. 대답에서 더 명확하게했습니다.
Alexander O'Mara

또한 이것을 삭제하기로 투표 한 사람은 답변 삭제 지침을 검토 하십시오 .
Alexander O'Mara

1

ES6에는 Tagged Template Literals가 있습니다.

예를 들면 다음과 같습니다.

function foo(val) {
    console.log(val);
}

foo`Tagged Template Literals`;


3
실제로 이것은 귀하의 1.5 년 전에 게시 한 답변에 있습니다 ... 왜 새로운 답변이 필요한지 확실하지 않습니까?
trincot

2
지금 같은 것을 구현하려는 다른 사람들이 새로운 답변을 사용할 수 있기 때문입니다.
mehta-rohan

3
@ mehta-rohan, 나는 그 의견을 이해하지 못합니다. 이것이 합리적이라면 왜 같은 대답을 반복해서 얻는가? 그것이 어떻게 유용한 지 알 수 없습니다.
trincot
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.