javascript - 같은 줄에서 익명의 함수를 호출해야하는 이유는 무엇입니까?


폐쇄에 대한 일부 게시물을 읽었을 때 어디에서나 이것을 보았지만 어떻게 작동하는지 명확하게 설명 할 수는 없었습니다. 매번 사용법을 설명 할 때마다 :

// Create a new anonymous function, to use as a wrapper
(function(){
    // The variable that would, normally, be global
    var msg = "Thanks for visiting!";

    // Binding a new function to a global object
    window.onunload = function(){
        // Which uses the 'hidden' variable
        alert( msg );
    };
// Close off the anonymous function and execute it
})();

우리는 새로운 익명의 함수를 생성하고 실행한다는 것을 알았습니다. 그래서이 간단한 코드가 작동해야합니다.

(function (msg){alert(msg)})('SO');

제 질문은 여기서 어떤 종류의 마술이 일어나는 것입니까? 나는 내가 다음과 같이 썼을 때 그것을 생각했다.

(function (msg){alert(msg)})

새로운 무명 함수는 함수 ""(msg)처럼 생성 될 것입니다 ...

그렇다면 왜 이것이 효과가 없습니까?

(function (msg){alert(msg)});
('SO');

왜 같은 줄에 있어야합니까?

몇 가지 게시물을 가르쳐 주시거나 설명을 주시겠습니까?



Answers



함수 정의 뒤에 세미콜론을 삭제하십시오.

(function (msg){alert(msg)})
('SO');

위가 효과가있다.

DEMO 페이지 : https://jsfiddle.net/e7ooeq6m/

나는이 게시물에서 이런 종류의 패턴을 논의했다.

jQuery와 $ questions

편집하다:

ECMA 스크립트 스펙 을 살펴보면 함수를 정의 할 수있는 3 가지 방법이 있습니다. (98 페이지, 13 절 기능 정의)

1. 함수 생성자 사용하기

var sum = new Function('a','b', 'return a + b;');
alert(sum(10, 20)); //alerts 30

2. 함수 선언 사용.

function sum(a, b)
{
    return a + b;
}

alert(sum(10, 10)); //Alerts 20;

3. 함수식

var sum = function(a, b) { return a + b; }

alert(sum(5, 5)); // alerts 10

그러면 선언과 표현의 차이는 무엇입니까?

ECMA 스크립트 사양에서 :

FunctionDeclaration : 함수 식별자 (FormalParameterListopt) {FunctionBody}

FunctionExpression : function Identifieropt (FormalParameterListopt) {FunctionBody}

눈에 잘 띄는 경우, '식별자'는 함수 표현식에 대해 선택적 입니다. 식별자를주지 않으면 익명의 함수를 만듭니다. 식별자를 지정할 수 없다는 의미는 아닙니다.

이것은 다음이 유효 함을 의미합니다.

var sum = function mySum(a, b) { return a + b; }

중요한 점은 'mySum'은 외부가 아닌 mySum 함수 본문에서만 사용할 수 있다는 것입니다. 다음 예제를 참조하십시오.

var test1 = function test2() { alert(typeof test2); }

alert(typeof(test2)); //alerts 'undefined', surprise! 

test1(); //alerts 'function' because test2 is a function.

라이브 데모

이것과 비교

 function test1() { alert(typeof test1) };

 alert(typeof test1); //alerts 'function'

 test1(); //alerts 'function'

이 지식으로 무장 한 코드를 분석 해보자.

당신이 좋아하는 코드를 가지고있을 때,

    function(msg) { alert(msg); }

함수 식을 만들었습니다. 그리고이 함수 표현식을 괄호 안에 싸서 실행할 수 있습니다.

    (function(msg) { alert(msg); })('SO'); //alerts SO.



자체 호출 함수라고합니다.

(function(){}) 을 호출 할 때 함수 객체를 반환하고 있습니다. 당신이 그것에 append () 할 때, 그것은 호출되고 몸체의 어떤 것이 실행된다. 그 ; 두 번째 호출이 실패하는 이유입니다.




내가 혼란스러워하는 한 가지는 "()"이 연산자를 그룹화한다는 것입니다.

다음은 기본 선언 된 함수입니다.

전의. 1:

var message = 'SO';

function foo(msg) {
    alert(msg);
}

foo(message);

함수는 객체이며 그룹화 할 수 있습니다. 그럼 함수 주위에 괄호를 던지자.

전의. 2 :

var message = 'SO';

function foo(msg) {  //declares foo
    alert(msg);
}

(foo)(message);     // calls foo

이제는 같은 함수를 선언하고 바로 호출하는 대신 기본 치환을 사용하여 선언 할 수 있습니다.

전의. 삼.

var message = 'SO';

(function foo(msg) {
    alert(msg);
})(message);          // declares & calls foo

마지막으로, 우리는 이름을 사용하지 않기 때문에 그 여분의 foo가 필요하지 않습니다! 함수는 익명 일 수 있습니다.

전의. 4.

var message = 'SO';

(function (msg) {   // remove unnecessary reference to foo
    alert(msg);
})(message);

질문에 대답하려면 예 2를 참조하십시오. 첫 번째 줄에서는 이름이없는 함수를 선언하고 그룹화하지만 호출하지 않습니다. 두 번째 행은 문자열을 그룹화합니다. 둘 다 아무것도하지 않습니다. (빈센트의 첫 번째 예.)

(function (msg){alert(msg)});  
('SO');                       // nothing.

(foo); 
(msg); //Still nothing.

그러나

(foo)
(msg); //works



익명의 함수는 이름이 ""인 함수가 아닙니다. 이것은 단순히 이름이없는 함수입니다.

JavaScript의 다른 값과 마찬가지로 함수에는 이름을 만들 필요가 없습니다. 다른 값과 마찬가지로 이름에 실제로 바인딩하는 것이 훨씬 더 유용하지만.

그러나 다른 값과 마찬가지로 이름에 바인딩하지 않고 사용하기를 원할 때도 있습니다. 그것이 바로 자기 발동 패턴입니다.

여기에는 함수와 숫자가 있고, 묶여 있지 않으며, 아무 것도하지 않고 결코 사용할 수 없습니다 :

function(){ alert("plop"); }
2;

따라서 다른 값과 마찬가지로 변수를 사용할 수 있도록 변수에 저장해야합니다.

var f = function(){ alert("plop"); }
var n = 2;

또한 syntatic sugar를 사용하여 함수를 변수에 바인딩 할 수 있습니다.

function f(){ alert("plop"); }
var n = 2;

그러나 이름을 지정하지 않아도 혼란과 가독성이 떨어지면 바로 사용할 수 있습니다.

(function(){ alert("plop"); })(); // will display "plop"
alert(2 + 3); // will display 5

여기서 내 함수와 숫자는 변수에 바인딩되지 않지만 여전히 사용할 수 있습니다.

이런 식으로, 자기 호출 함수는 실제 가치가없는 것처럼 보입니다. 그러나 자바 스크립트 스코프 구분 기호는 함수이며 블록 ({})이 아니라는 사실을 명심해야합니다.

따라서 자체 호출 함수는 실제로 C ++, C # 또는 Java 블록과 동일한 의미를 갖습니다. 즉, 내부에서 생성 된 변수가 범위 밖으로 "누설되지"않습니다. 전역 범위를 오염시키지 않기 위해 자바 스크립트에서 매우 유용합니다.




JavaScript가 작동하는 방식입니다. 명명 된 함수를 선언 할 수 있습니다.

function foo(msg){
   alert(msg);
}

그리고 그것을 부르십시오.

foo("Hi!");

또는 익명의 함수를 선언 할 수 있습니다.

var foo = function (msg) {
    alert(msg);
}

그리고 전화 :

foo("Hi!");

또는 함수를 이름에 바인딩 할 수 없습니다.

(function(msg){
   alert(msg);
 })("Hi!");

함수는 함수를 반환 할 수도 있습니다.

function make_foo() {
    return function(msg){ alert(msg) };
}

(make_foo())("Hi!");

make_foo 의 본문에서 "var"로 정의 된 변수는 make_foo 가 반환 한 각 함수에 의해 닫힐 가치가 없습니다. 이것은 클로저 (closure)이며, 하나의 함수에 의해 변경된 값이 다른 함수에 의해 변경 될 수 있음을 의미합니다.

원하는 경우 정보를 캡슐화 할 수 있습니다.

function make_greeter(msg){
    return function() { alert(msg) };
}

var hello = make_greeter("Hello!");

hello();

자바는 거의 모든 프로그래밍 언어가 작동하지만 자바는 작동합니다.




표시하는 코드,

(function (msg){alert(msg)});
('SO');

문장으로 구성됩니다. 첫 번째는 함수 객체를 생성하는 표현식입니다 (저장되지 않기 때문에 가비지 수집됩니다). 두 번째는 문자열을 생성하는 표현식입니다. 함수를 문자열에 적용하려면 문자열을 함수의 인수로 함수에 전달해야합니다 (위에서 설명한 것처럼). 또는 실제로 함수를 변수에 저장해야 할 수 있습니다. 나중에, 여가 시간에 그것을 적용하십시오. 이렇게 :

var f = (function (msg){alert(msg)});
f('SO');

익명의 함수 (λ 함수)를 변수에 저장함으로써 효과적으로 이름을 부여합니다. 따라서 정규 함수를 정의 할 수도 있습니다.

function f(msg) {alert(msg)};
f('SO');



이전 의견 요약 :

function() {
  alert("hello");
}();

변수에 할당되지 않으면 구문 오류가 발생합니다. 이 코드는 닫는 괄호를 구문 적으로 올바르지 않게 만드는 함수 문 (또는 정의)으로 구문 분석됩니다. 함수 부분에 괄호를 추가하면 인터프리터 (및 프로그래머)에게 이것이 함수 표현 (또는 호출)임을 알립니다.

(function() {
  alert("hello");
})();

이는 자체 호출 함수입니다. 즉, 호출이 익명으로 선언 된 동일한 행에서 호출되기 때문에 익명으로 생성되어 즉시 실행됩니다. 이 자체 호출 함수는 인수가없는 함수를 호출하는 익숙한 구문과 함수의 이름을 둘러싼 괄호로 표시됩니다. (myFunction)(); .

좋은 SO 토론 JavaScript 함수 구문이 있습니다.




이 대답은 엄격하게 질문과 관련이 없지만 이러한 종류의 구문 기능이 기능에만 국한된 것은 아닙니다. 예를 들어, 우리는 항상 다음과 같이 할 수 있습니다 :

alert(
    {foo: "I am foo", bar: "I am bar"}.foo
); // alerts "I am foo"

기능 관련. Function.prototype에서 상속받은 객체이므로 다음과 같은 작업을 수행 할 수 있습니다.

Function.prototype.foo = function () {
    return function () {
        alert("foo");
    };
};

var bar = (function () {}).foo();

bar(); // alerts foo

그리고 여러분도 알다시피, 우리는 함수를 실행하기 위해 괄호로 함수를 둘러 쌀 필요조차 없습니다. 어쨌든, 변수에 결과를 할당하려고하는 한.

var x = function () {} (); // this function is executed but does nothing

function () {} (); // syntax error

함수를 선언하는 즉시 함수를 사용하여 할 수있는 또 하나의 작업은 함수를 통해 new 연산자를 호출하고 객체를 얻는 것입니다. 다음은 동일합니다.

var obj = new function () {
    this.foo = "bar";
};

var obj = {
    foo : "bar"
};



JavaScript 기능이 하나 더 있습니다. 동일한 익명 함수를 재귀 적으로 호출하려는 경우.

(function forInternalOnly(){

  //you can use forInternalOnly to call this anonymous function
  /// forInternalOnly can be used inside function only, like
  var result = forInternalOnly();
})();

//this will not work
forInternalOnly();// no such a method exist



질문자 질문에 대한 나의 이해는 다음과 같습니다.

이 마술은 어떻게 작동합니까?

(function(){}) ('input')   // Used in his example

나는 틀릴지도 모른다. 그러나 사람들이 잘 알고있는 일반적인 습관은 다음과 같습니다.

(function(){}('input') )

그 이유는 JavaScript 괄호 AKA () 가 문장을 포함 할 수 없기 때문이며 파서가 function 키워드를 만날 때 함수 선언이 아닌 함수 표현식으로 구문 분석한다는 것을 알 수 있습니다.

출처 : 블로그 게시물 즉시 호출 된 함수 식 (IIFE)




대괄호가없는 예 :

void function (msg) { alert(msg); }
('SO');

(이것은 공허의 유일한 실제 사용이다, afaik)

또는

var a = function (msg) { alert(msg); }
('SO');

또는

!function (msg) { alert(msg); }
('SO');

잘 작동한다. void 로 인해 표현식이 평가되고, 과제와 강타가 평가됩니다. 마지막 연산자는 ~ , + , - , delete , typeof , 단항 연산자 중 일부 ( void 도 하나임)와 함께 작동합니다. 변수가 필요하기 때문에 작동하지 않는 것은 ++ 입니다.

줄 바꿈은 필요하지 않습니다.




자체 실행 익명 기능입니다. 첫 번째 대괄호 집합은 실행할 표현식을 포함하고 두 번째 대괄호 집합은 해당 표현식을 실행합니다.

(function () {
    return ( 10 + 20 );
})();

Peter Michaux 는 중요한 괄호 쌍의 차이점에 대해 설명합니다.

부모 네임 스페이스에서 변수를 숨길 때 유용합니다. 함수 내의 모든 코드는 함수의 사적인 영역에 포함되어 있습니다. 즉, 함수의 외부에서 전혀 액세스 할 수 없으므로 실제로는 private이됩니다.

만나다:

  1. 폐쇄 (컴퓨터 과학)
  2. JavaScript 네임 스페이스
  3. 중요한 쌍의 자바 괄호



그것이 작동하지 않는 이유는 단순한 이유 때문이 아닙니다 ; 익명 함수의 끝을 나타냅니다. 함수 호출이 끝나면 () 가 없기 때문에 함수 호출이 아니기 때문입니다. 그건,

function help() {return true;}

result = help(); 를 호출 result = help(); 이 함수를 호출하고 true를 반환합니다.

result = help; 를 호출 result = help; 이것은 전화가 아닙니다. 도움말을 결과에 할당 할 데이터처럼 취급하는 지정입니다.

네가 한 일은 세미콜론을 추가하여 익명의 함수를 선언 / 인스턴스화하는 것이 었습니다.

(function (msg) { /* Code here */ });

다음 그냥 괄호를 사용하여 다른 진술에서 그것을 호출하려고 ... 분명히 있기 때문에 함수는 이름이 있지만이 작동하지 않습니다 :

('SO');

인터프리터는 두 번째 라인의 괄호를 새로운 명령어 / 명령문으로 간주하므로 다음과 같이하더라도 작동하지 않습니다.

(function (msg){/*code here*/});('SO');

여전히 작동하지 않지만 인터프리터가 공백과 캐리지를 무시하고 전체 코드를 하나의 명령문으로 간주하므로 세미콜론을 제거하면 작동합니다.

(function (msg){/*code here*/})        // This space is ignored by the interpreter
('SO');

결론 : 함수 호출은 다른 함수에 의해 호출되는 것과 같은 특별한 조건 하에서는 끝 부분에 () 가없는 함수 호출이 아닙니다. 즉, 괄호가 포함되지 않았더라도 onload = 'help'는 도움말 함수를 실행합니다. 나는 setTimeout과 setInterval도이 유형의 함수 호출을 허용한다고 생각하며, 인터프리터는 "함수 호출이 괄호없이 함수 호출이 아닌"장면으로 돌아가는 괄호를 추가한다고 생각한다.




(function (msg){alert(msg)})
('SO');

익명 함수를 많은 JavaScript 프레임 워크가 사용하는 클로저로 사용하는 일반적인 방법입니다.

이 함수는 코드가 컴파일 될 때 자동으로 호출됩니다.

배치하는 경우 ; 첫 번째 줄에서 컴파일러는이를 두 개의 다른 줄로 처리했습니다. 따라서 위와 같은 결과를 얻을 수 없습니다.

이것은 또한 다음과 같이 쓰여질 수 있습니다 :

(function (msg){alert(msg)}('SO'));

자세한 내용은 JavaScript / 익명 함수 를 참조하십시오.




  1. 익명 함수는 런타임에 동적으로 선언되는 함수입니다. 일반 함수와 같은 방식으로 이름이 주어지지 않기 때문에 익명 함수라고합니다.

    익명 함수는 함수 선언 대신 함수 연산자를 사용하여 선언됩니다. 함수 연산자를 사용하여 표현식을 넣을 때마다 새 함수를 만들 수 있습니다. 예를 들어 새 함수를 함수 호출의 매개 변수로 선언하거나 다른 객체의 속성을 할당 할 수 있습니다.

    다음은 명명 된 함수의 일반적인 예입니다.

    function flyToTheMoon () {경고 ( "줌! 줌! 줌!"); } flyToTheMoon (); 다음은 익명 함수로 만든 동일한 예제입니다.

    var flyToTheMoon = function () {alert ( "줌! 줌! 줌!"); } flyToTheMoon ();

    자세한 내용은 다음을 참조하십시오 :

    http://helephant.com/2008/08/23/javascript-anonymous-functions/




IIFE는 단순히 함수를 분류하고 전역 변수 이름 공간을 "오염"시키지 않도록 msg 변수를 숨 깁니다. 실제로 10 억 달러 규모의 웹 사이트를 구축하지 않는 한 단순하게 유지하고 아래처럼하십시오.

var msg = "later dude";
window.onunload = function(msg){
  alert( msg );
};

Revealing Module Pattern을 사용하여 msg 속성의 네임 스페이스를 msg 수 있습니다.

var myScript = (function() {
    var pub = {};
    //myscript.msg
    pub.msg = "later dude";
    window.onunload = function(msg) {
        alert(msg);
    };
    //API
    return pub;
}());



익명 함수는 사용자가 제공하는 입력에서 사용자로부터 출력을 생성 할 수 있도록 함수를 즉시 정의하는 일회성 계약을 의미합니다. 당신이 입력을 제공하지 않았다는 것을 제외하고. 대신, 당신은 두 번째 줄 ( 'SO')에 무언가를 썼습니다. - 함수와 아무런 관련이없는 독립 선언문. 너는 무엇을 기대 했는가? :)




또 다른 관점

먼저 익명의 함수를 선언 할 수 있습니다.

var foo = function(msg){
 alert(msg);
}

그런 다음 호출 :

foo ('Few');

왜냐하면 foo = function (msg) {alert (msg);} 그래서 foo 를 다음과 같이 바꿀 수 있습니다 :

function(msg){
 alert(msg);
} ('Few');

그러나 파싱 할 때 함수를 선언 할 때 구문 오류가 발생하지 않도록 전체 익명 함수를 중괄호 쌍으로 묶어야합니다. 그런 다음,

(function(msg){
 alert(msg);
}) ('Few');

이렇게하면 나를 쉽게 이해할 수 있습니다.




당신이했을 때 :

(function (msg){alert(msg)});
('SO');

세미콜론 때문에 함수를 끝냈습니다 ('SO') . 다음과 같이 작성하면

(function (msg){alert(msg)})
('SO');

효과가있을 것입니다.

실례 : http://jsfiddle.net/oliverni/dbVjg/