[javascript] 캡슐화 된 익명 함수 구문 설명

요약

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);
}();

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



답변

로 구문 분석되고 있기 때문에 작동하지 않으며 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;
};


답변

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

그래도 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
};

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


답변

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

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(){})()..


답변

자바 스크립트에서는이를 즉시 호출 된 함수 표현식 (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);

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


답변

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

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

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

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

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


답변

아마도 더 짧은 대답은

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

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

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

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


답변

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

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

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

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