캡슐화 된 익명 함수 구문 설명


372

요약

JavaScript로 캡슐화 된 익명 함수에 대한 구문의 이유를 설명 할 수 있습니까? 왜 이것이 효과 (function(){})();function(){}();있습니까?


내가 아는데 것을

JavaScript에서 다음과 같은 명명 된 함수를 만듭니다.

function twoPlusTwo(){
    alert(2 + 2);
}
twoPlusTwo();

익명 함수를 만들어 변수에 할당 할 수도 있습니다.

var twoPlusTwo = function(){
    alert(2 + 2);
};
twoPlusTwo();

익명 함수를 만든 다음 대괄호로 묶고 즉시 실행하여 코드 블록을 캡슐화 할 수 있습니다.

(function(){
    alert(2 + 2);
})();

이것은 Greasemonkey 스크립트, jQuery 플러그인 등과 같이 잠재적으로 충돌하는 변수로 현재 범위 또는 전역 범위를 어지럽히 지 않도록 모듈 식 스크립트를 만들 때 유용합니다.

이제 이것이 왜 작동하는지 이해합니다. 괄호는와 같이 내용을 묶고 결과 만 표시합니다 (나는 그것을 설명하는 더 좋은 방법이 있다고 확신합니다) (2 + 2) === 4.


내가 이해하지 못하는 것

그러나 이것이 왜 똑같이 작동하지 않는지 이해하지 못합니다.

function(){
    alert(2 + 2);
}();

저에게 설명해 주시겠습니까?


39
나는 이러한 다양한 표기법과 함수를 정의 / 설정 / 호출하는 방법이 처음에 자바 스크립트 작업의 가장 혼란스러운 부분이라고 생각합니다. 사람들은 그들에 대해 이야기하지 않는 경향이 있습니다. 가이드 나 블로그에서 강조되지는 않습니다. 그것은 대부분의 사람들에게 혼란 스러우며 js에 유창한 사람들도 그것을 통과해야하기 때문에 내 마음을 아프게합니다. 결코 말하지 않는이 빈 금기 현실과 같습니다.
ahnbizcad 2016 년

1
또한 읽어 이 구조의 목적 , 또는 (검사 기술 ) 설명 (도 여기에 ). 괄호 배치에 대해서는 해당 위치에 대한 이 질문을 참조하십시오 .
Bergi

OT :이 익명 함수가 많이 사용되는 경우 알고 싶은 것들에 대한 참조하시기 바랍니다 adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html
알리레자 Fattahi

이는 IIFE (Immediately Invoked Function Expressions)의 일반적인 경우입니다.
Aminu Kano

답변:


410

로 구문 분석되고 있기 때문에 작동하지 않으며 FunctionDeclaration함수 선언의 이름 식별자는 필수 입니다.

괄호로 묶으면로 평가되며 FunctionExpression함수 표현식의 이름을 지정할 수 있습니다.

문법은 FunctionDeclaration다음과 같습니다.

function Identifier ( FormalParameterListopt ) { FunctionBody }

그리고 FunctionExpressions :

function Identifieropt ( FormalParameterListopt ) { FunctionBody }

보시다시피 Identifier(Identifier opt ) 토큰 FunctionExpression은 선택 사항이므로 이름을 정의하지 않고 함수 표현식을 가질 수 있습니다.

(function () {
    alert(2 + 2);
}());

또는 명명 된 함수 표현식 :

(function foo() {
    alert(2 + 2);
}());

괄호 (공식적으로 그룹화 연산자 라고 함 )는 표현식 만 둘러 쌀 수 있으며 함수 표현식이 평가됩니다.

두 개의 문법 제작은 모호 할 수 있으며 다음과 같이 정확하게 똑같이 보일 수 있습니다.

function foo () {} // FunctionDeclaration

0,function foo () {} // FunctionExpression

구문 분석기는 표시 되는 컨텍스트 에 따라 a FunctionDeclaration또는 a 인지 알고 있습니다.FunctionExpression

위의 예에서 쉼표 연산자 는 표현식 만 처리 할 수 있으므로 두 번째 표현식은 표현식입니다.

반면에, FunctionDeclarations는 실제로 " Program"코드, 즉 전역 범위 외부 및 FunctionBody다른 함수 내부의 코드를 의미하는 코드 에만 나타날 수 있습니다.

블록 내부의 함수는 다음과 같은 예기치 않은 동작을 유발할 수 있으므로 피해야합니다.

if (true) {
  function foo() {
    alert('true');
  }
} else {
  function foo() {
    alert('false!');
  }
}

foo(); // true? false? why?

위의 코드는 실제로 명령문을 포함 할 수 SyntaxError있기 때문에 실제로는을 생성해야 Block하지만 ECMAScript 사양은 함수 명령문을 정의하지 않습니다. 그러나 대부분의 구현은 허용되며 두 번째 함수 인 간단하게 경고합니다 'false!'.

Mozilla 구현 (Rhino, SpiderMonkey)은 다른 동작을합니다. 이들의 문법에는 비표준 함수 명령문이 포함되어 있습니다. 이는 함수가 s에서 발생하는 구문 분석 시간이 아니라 런타임에 평가됨을 의미합니다 FunctionDeclaration. 이러한 구현에서 첫 번째 함수가 정의됩니다.


함수는 다른 방식으로 선언 될 수 있으며 다음을 비교하십시오 .

1- 변수에 곱한 함수 생성자로 정의 된 함수 곱하기 :

var multiply = new Function("x", "y", "return x * y;");

2- multiply 라는 함수의 함수 선언 :

function multiply(x, y) {
    return x * y;
}

3- 변수에 곱한 함수 표현식 :

var multiply = function (x, y) {
    return x * y;
};

4- 변수에 곱하는 명명 된 함수 표현식 func_name :

var multiply = function func_name(x, y) {
    return x * y;
};

2
CMS의 답변이 맞습니다. 함수 선언과 표현식에 대한 자세한 설명은 kangax의이 기사를 참조하십시오 .
Tim Down

이것은 좋은 대답입니다. 소스 텍스트를 구문 분석하는 방법과 BNF의 구조와 밀접하게 연결된 것으로 보입니다. 귀하의 예 3에서, 그것이 등식 기호를 따르기 때문에 함수 표현식이라고 말할까요? 이름이없는 함수 선언으로 해석 되었는가? 변수에 변수를 지정하거나 이름을 지정하거나 호출하지 않으면 어떤 목적으로 사용됩니까?
Breton

1
아하. 매우 유용한. 감사합니다, CMS. 여러분이 링크 한 Mozilla 문서의이 부분은 특히
밝습니다

1
+1, 함수 표현식에서 닫는 괄호가 잘못된 위치에
있었지만

1
@GovindRai, No. 함수 선언은 컴파일 타임에 처리되며 중복 함수 선언은 이전 선언보다 우선합니다. 런타임에 함수 선언을 이미 사용할 수 있으며이 경우 사용 가능한 것은 "false"를 알리는 것입니다. 자세한 내용 은 JS
Saurabh Misra

50

이것은 오래된 질문과 답변이지만 오늘날 많은 개발자들이 루프를 던지는 주제에 대해 설명합니다. 나는 나에게 함수 선언과 함수 표현식의 차이 말할 수있는 자바 스크립트 개발자 후보 내가 인터뷰 한의 수를 셀 수 없다 하고 있는 즉시 호출 함수 표현식이 무엇인지 단서가 없었다 있습니다.

그래도 Premasagar의 코드 스 니펫에 이름 식별자를 부여해도 작동하지 않는다는 매우 중요한 점을 언급하고 싶습니다.

function someName() {
    alert(2 + 2);
}();

이것이 작동하지 않는 이유는 JavaScript 엔진이 이것을 함수 선언으로 해석하고 표현식이 포함되지 않은 완전히 관련되지 않은 그룹화 연산자를 해석하고 그룹화 연산자 표현식을 포함 해야 하기 때문입니다. JavaScript에 따르면 위의 코드 조각은 다음 코드 조각과 같습니다.

function someName() {
    alert(2 + 2);
}

();

일부 사람들에게 유용 할 수있는 또 다른 점은 함수 정의 자체를 제외하고 코드의 맥락에서 함수 표현식에 제공하는 이름 식별자가 거의 쓸모가 없다는 것입니다.

var a = function b() {
    // do something
};
a(); // works
b(); // doesn't work

var c = function d() {
    window.setTimeout(d, 1000); // works
};

물론 함수 정의와 함께 이름 식별자를 사용하면 코드 디버깅과 관련하여 항상 도움이되지만 완전히 다른 것입니다 : :-)


17

큰 답변이 이미 게시되었습니다. 그러나 함수 선언은 빈 완료 레코드를 반환합니다.

14.1.20-런타임 의미론 : 평가

FunctionDeclaration : function BindingIdentifier 형식 ( 매개 변수 ) { FunctionBody }

  1. 정상 완료 (비어 있음)를 반환합니다 .

반환 된 값을 얻는 대부분의 방법은 함수 선언을 함수 표현식으로 변환하기 때문에이 사실은 관찰하기 쉽지 않습니다. 그러나 eval그것을 보여줍니다 :

var r = eval("function f(){}");
console.log(r); // undefined

빈 완료 레코드를 호출하는 것은 의미가 없습니다. 그것이 function f(){}()작동하지 않는 이유 입니다. 실제로 JS 엔진은이를 호출하려고 시도하지 않으며 괄호는 다른 문의 일부로 간주됩니다.

그러나 함수를 괄호로 묶으면 함수 표현식이됩니다.

var r = eval("(function f(){})");
console.log(r); // function f(){}

함수 표현식은 함수 객체를 반환합니다. 따라서 다음과 같이 호출 할 수 있습니다 (function f(){})()..


이 답변이 간과되는 것은 부끄러운 일입니다. 허용되는 답변만큼 포괄적이지는 않지만 매우 유용한 추가 정보를 제공하고 더 많은 투표를받을 가치가 있습니다.
Avrohom Yisroel

10

자바 스크립트에서는이를 즉시 호출 된 함수 표현식 (IIFE)이라고 합니다.

함수 표현식으로 만들려면 다음을 수행하십시오.

  1. ()를 사용하여 묶습니다.

  2. 무효 연산자를 배치하기

  3. 변수에 할당하십시오.

그렇지 않으면 함수 정의로 취급되며 다음과 같은 방법으로 함수를 동시에 호출 / 호출 할 수 없습니다.

 function (arg1) { console.log(arg1) }(); 

위의 오류가 발생합니다. 함수 표현식 만 즉시 호출 할 수 있기 때문입니다.

몇 가지 방법으로 달성 할 수 있습니다. 방법 1 :

(function(arg1, arg2){
//some code
})(var1, var2);

방법 2 :

(function(arg1, arg2){
//some code
}(var1, var2));

방법 3 :

void function(arg1, arg2){
//some code
}(var1, var2);

방법 4 :

  var ll = function (arg1, arg2) {
      console.log(arg1, arg2);
  }(var1, var2);

위의 모든 것은 즉시 함수 표현식을 호출합니다.


3

또 다른 작은 말이 있습니다. 코드는 약간만 변경하면 작동합니다.

var x = function(){
    alert(2 + 2);
}();

더 널리 퍼진 버전 대신 위의 구문을 사용합니다.

var module = (function(){
    alert(2 + 2);
})();

vim에서 javascript 파일에 대해 들여 쓰기가 올바르게 작동하지 않았기 때문입니다. vim은 열린 괄호 안의 중괄호를 좋아하지 않는 것 같습니다.


실행 된 결과를 변수에 할당하지만 독립형이 아닌 경우이 구문이 작동하는 이유는 무엇입니까?
paislee

1
@paislee-JavaScript 엔진은 function키워드로 시작하는 유효한 JavaScript 문을 함수 선언 으로 ()해석하므로 후행 은 JavaScript 구문 규칙에 따라 JavaScript 표현식 만 포함 할 수 있고 포함 해야하는 그룹화 연산자 로 해석됩니다 .
natlee75

1
@bosonix-선호하는 구문은 잘 작동하지만 참조한 "더 널리 퍼진 버전"또는 ()일관성을 위해 그룹화 연산자 (Douglas Crockford가 강력하게 권장하는) 내에 포함 된 변형을 사용 하는 것이 좋습니다. 변수에 할당하지 않고 IIFE를 사용하는 것이 일반적이며, 일관되게 사용하지 않으면 래핑 괄호를 포함하는 것을 잊어 버리기 쉽습니다.
natlee75

0

아마도 더 짧은 대답은

function() { alert( 2 + 2 ); }

(익명) 함수 를 정의 하는 함수 리터럴 입니다 . 표현식으로 해석되는 추가 () 쌍은 최상위 수준이 아니라 리터럴 만 예상됩니다.

(function() { alert( 2 + 2 ); })();

표현 문익명 함수 를 호출 에 있습니다.


0
(function(){
     alert(2 + 2);
 })();

괄호 안에 전달 된 것은 함수 표현식으로 간주되므로 위의 유효한 구문입니다.

function(){
    alert(2 + 2);
}();

위의 구문은 유효하지 않습니다. Java 스크립트 구문 분석기는 오류를 발생시키는 항목을 찾지 못하므로 함수 키워드 다음에 함수 이름을 찾습니다.


2
귀하의 답변이 정확하지는 않지만 허용되는 답변은 이미이 모든 내용을 다루고 있습니다.
Arnold

0

다음과 같이 사용할 수도 있습니다.

! function() { console.log('yeah') }()

또는

!! function() { console.log('yeah') }()

!-neg op는 fn 정의를 fn 표현식으로 변환하므로을 사용하여 즉시 호출 할 수 있습니다 (). 0,fn def또는 사용 과 동일void fn def


-1

그들은 같은 매개 변수 인수와 함께 사용할 수 있습니다

var x = 3; 
var y = 4;

(function(a,b){alert(a + b)})(x,y)

7로 결과


-1

이러한 추가 괄호는 전역 네임 스페이스와 코드가 포함 된 익명 함수 사이에 추가 익명 함수를 만듭니다. 그리고 다른 함수 안에 선언 된 Javascript 함수는이를 포함하는 부모 함수의 네임 스페이스에만 액세스 할 수 있습니다. 전역 범위와 실제 코드 범위 사이에 추가 개체 (익명 기능)가 있으므로 유지되지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.