(function () {}) () 구조는 어떻게 작동하며 사람들이 왜 그것을 사용합니까?


79

(function() {})()jQuery에 특화된 사촌 (function($) {})(jQuery)은 자바 스크립트 코드에서 항상 팝업됩니다.

이러한 구성은 어떻게 작동하며 어떤 문제를 해결합니까?

감사의 예



2
정확한 중복이 아닙니다. 다른 질문에 대한 답변은 왜 하나 jQuery가 논쟁으로 제공 하는지를 말하지 않습니다 .
Georg Schölly

1
나는 항상 여분의 괄호가 필요한 이유를 궁금해했습니다. 중괄호를 사용하는 블록과 객체 리터럴 사이의 모호성과 관련이 있다고 생각합니다. var x = function () {} ()처럼 잘 작동하는 것과 같이 무언가에 할당하는 경우에는 필요하지 않습니다.
jpsimons

1
왜 이것이 '진짜 질문이 아닌 것으로 종료'입니까? 질문은 명확하고 관련성이 있습니다.
Chris

답변:


73

JavaScript 프레임 워크의 인기가 높아짐에 따라이 $기호는 다양한 경우에 사용되었습니다. 따라서 가능한 충돌을 줄이기 위해 다음 구성을 사용할 수 있습니다.

(function ($){
  // Your code using $ here.
})(jQuery);

특히, 이것은 주 jQuery 객체를 매개 변수로 전달하는 즉시 실행되는 익명 함수 선언입니다 . 해당 함수 내 에서 다른 프레임 워크가 범위에 있는지 걱정하지 않고 해당 개체를 참조하는 데 사용할 수 있습니다 .$


4
짧고 의미있는 답변. +1!
pestaa

5
기술적으로는 함수 표현식 (! 선언)입니다. IIFE
John Strickler

"... 다른 프레임 워크도 범위 내에있는 것에 대해 걱정하지 않고."라는 의미를 설명 할 수 있습니까?
Redtopia

@Redtopia. 자바 스크립트 범위는 함수 수준에서 정의됩니다. 함수 외부의 모든 것은 전역 범위에 있습니다. 웹 페이지에 얼마나 많은 Javascript가 포함되어 있는지 생각해보십시오. 함수 범위 외부의 각 변수는 충돌이 심합니다.
Alberto De Caro

명확히 해주셔서 감사합니다. 전역 범위 나 다른 함수의 범위에서 볼 수없는 익명 함수의 로컬 범위를 언급하고 있다는 것이 분명하지 않았습니다.
Redtopia

41

이것은 변수 범위를 제한하는 데 사용되는 기술입니다. 변수가 전역 네임 스페이스를 오염시키는 것을 방지하는 유일한 방법입니다.

var bar = 1; // bar is now part of the global namespace
alert(bar);

(function () {
   var foo = 1; // foo has function scope
   alert(foo); 
   // code to be executed goes here
})();

7
... 코드와 관련하여 여전히 "전역 적"이어야합니다.
tvanfosson

그렇다면 예제 코드에서 Opera에 대한 참조는 관련이 없거나 잘못 되었습니까?
Bobby Jack

1
@Bobby : 해당 블록 내에 Opera에만 사용되는 추가 변수 / 함수가있을 수 있습니다.
geowa4

19

1) 익명 함수를 정의하고 바로 실행합니다.

2) 일반적으로 원치 않는 코드로 전역 네임 스페이스를 오염시키지 않도록 수행됩니다.

3) 당신은 그것으로부터 몇 가지 메소드를 노출해야합니다. 내부 선언은 "비공개"입니다. 예를 들면 :

MyLib = (function(){
    // other private stuff here
    return {
        init: function(){
        }
    };

})();

또는, 또는 :

MyLib = {};
(function({
    MyLib.foo = function(){
    }
}));

요점은 여러 가지 방법으로 사용할 수 있지만 결과는 동일하다는 것입니다.


1. 이러한 함수는 별도의 파일에 정의되어 있는데 어떻게 실행됩니까? (누구도이 함수를 호출하지 않는 것 같으므로 함수가 트리거되는 방법은 무엇입니까?) 2. 최상위 수준의 함수에 "return"문이있는 것을 보지 못했습니다. dojo.util._doh를 읽고 있습니다. ._browserRunner.js 감사합니다!

1) 내가 말했듯이, 그것은 스스로 실행되고, 마지막 ()은 그것을 실행하도록 지시합니다. 2) 반드시 반환을 가질 필요는 없으며 특정 속성에 값을 설정할 수도 있습니다. 다른 가능성으로 답변을 업데이트 한 예일뿐입니다.
Evan Trimboli

9

즉시 호출되는 익명 함수입니다. 먼저 함수를 만든 다음 호출하면 동일한 효과를 얻을 수 있습니다.

(function(){ ... })();

다음과 같이 작동합니다.

temp = function(){ ... };
temp();

명명 된 함수를 사용하여 동일한 작업을 수행 할 수도 있습니다.

function temp() { ... }
temp();

jQuery 특정이라고 부르는 코드는 jQuery 객체를 사용한다는 의미에서만 가능합니다. 즉시 호출되는 매개 변수가있는 익명 함수입니다.

두 단계로 동일한 작업을 수행 할 수 있으며 원하는 매개 변수로 수행 할 수 있습니다.

temp = function(answer){ ... };
temp(42);

이것이 해결하는 문제는 함수의 코드에 대한 클로즈를 생성한다는 것입니다. 전역 네임 스페이스를 오염시키지 않고 변수를 선언 할 수 있으므로 한 스크립트를 다른 스크립트와 함께 사용할 때 충돌 위험을 줄일 수 있습니다.

jQuery의 특정 경우에는 이름 $를 jQuery의 별칭으로 선언하지 않는 호환성 모드에서 사용합니다. jQuery 객체를 클로저로 보내고 매개 변수 이름을 $로 지정하면 호환성 모드없이 동일한 구문을 사용할 수 있습니다.


@spoulson의 답변에 대해 언급했듯이 익명 함수는 클로저와 동일하지 않습니다.
Tim Down

7

여기 에서 첫 번째 구성이 변수에 대한 범위를 제공한다고 설명 합니다.

변수는 자바 스크립트의 함수 수준에서 범위가 지정됩니다. 이것은 변수가 블록으로 범위가 지정된 C # 또는 Java와 같은 언어에서 익숙한 것과 다릅니다. 이것이 의미하는 바는 루프 또는 if 문 내에서 변수를 선언하면 전체 함수에서 사용할 수 있다는 것입니다.

함수 내에서 변수의 범위를 명시 적으로 지정해야하는 경우 익명 함수를 사용하여이를 수행 할 수 있습니다. 실제로 익명 함수를 만든 다음 바로 실행할 수 있으며 내부의 모든 변수는 익명 함수로 범위가 지정됩니다.

(function() {
  var myProperty = "hello world";
  alert(myProperty);
})();
alert(typeof(myProperty)); // undefined

6

이를 수행하는 또 다른 이유 $는 사용 중인 프레임 워크의 연산자에 대한 혼란을 제거하는 것 입니다. 예를 들어 jQuery를 강제하려면 다음을 수행하십시오.

;(function($){
   ... your jQuery code here...
})(jQuery);

$연산자를 매개 변수로 전달하고 jQuery에서 호출하면 $다른 프레임 워크가로드 된 경우에도 함수 내의 연산자가 jQuery에 잠 깁니다.


원래 질문에 대한보다 구체적인 변형이지만 여전히 좋은 정보입니다! :)
Bobby Jack

전혀 대답은 아니지만, 당신이 가진 멋진 아이디어를 위해 그것을 올렸습니다!
Spidey

5

이 구조의 또 다른 용도는 클로저에 사용될 지역 변수의 값을 "캡처"하는 것입니다. 예를 들면 :

for (var i = 0; i < 3; i++) {
    $("#button"+i).click(function() {
        alert(i);
    });
}

위의 코드는 세 개의 버튼이 모두 "3"으로 팝업되도록합니다. 반면에 :

for (var i = 0; i < 3; i++) {
    (function(i) {
        $("#button"+i).click(function() {
            alert(i);
        });
    })(i);
}

이렇게하면 예상대로 세 개의 버튼이 "0", "1", "2"로 표시됩니다.

그 이유는 클로저 가 해당 변수의 현재 값을 보유하는 둘러싸는 스택 프레임에 대한 참조를 유지하기 때문 입니다. 클로저가 실행되기 전에 이러한 변수가 변경되면 클로저는 클로저가 생성 된 시점의 값이 아닌 최신 값만 볼 수 있습니다. 위의 두 번째 예에서와 같이 다른 함수 안에 클로저 생성을 래핑하면 변수의 현재 값 i이 익명 함수의 스택 프레임에 저장됩니다.


작은 멍청이이지만 닫힌 스택 프레임이 아니라 주변 어휘 범위입니다. 클로저의 좋은 구현은 클로저 내부에 실제로 언급 된 기호 만 캡처하고 일부 구현은 단순히 모든 것을 캡처합니다. OOP에서 객체에 대해 생각하는 한 가지 방법은 캡처 된 기호가 명시 적으로 정의되는 클로저 (객체의 멤버 속성)입니다.
KayEss

그것은 사실이지만 그것은 실제로 구현 문제이며 개념적으로 스택 프레임이 클로저에 의해 참조되는 것이라고 생각할 수 있습니다. Lisp 계열 언어의 OOP 스타일 "객체"는 모두 클로저로 수행되며 강력한 기술입니다.
Greg Hewgill

예, 스택 프레임의 관점에서 생각하고 싶다면 클로저는 스택 프레임의 체인이며, 전역 범위와 함께 어휘 범위의 각 둘러싸는 함수에 대해 하나의 프레임입니다. 어휘 범위는 여러 수준의 중첩 함수가있을 때 어떤 스택 프레임에 대해 무의미한 (그리고 오해의 소지가있는) 토론을하지 않기 때문에 (특히 클로저를 처음 접하는 사람에게 설명 할 때) 생각하기가 더 쉽습니다. 어휘 범위는 단순히 소스 코드에서 보는 것입니다.
KayEss

4

이것은 폐쇄 로 간주됩니다 . 포함 된 코드가 자체 어휘 범위 내에서 실행됨을 의미합니다. 즉, 새 변수와 함수를 정의 할 수 있으며 클로저 외부의 코드에서 사용되는 네임 스페이스와 충돌하지 않습니다.

var i = 0;
alert("The magic number is " + i);

(function() {
   var i = 99;
   alert("The magic number inside the closure is " + i);
})();

alert("The magic number is still " + i);

이렇게하면 세 개의 팝업이 생성 i되어 클로저의가 같은 이름의 기존 변수를 변경하지 않음을 보여줍니다 .

  • 매직 넘버는 0
  • 클로저 내부의 매직 넘버는 99입니다.
  • 매직 넘버는 여전히 0

5
이것은 클로저가 아니라 단순히 함수에 자체 범위가 있음을 보여주는 것입니다. 클로저는 함수가 다른 함수 내부에 정의 되고 해당 함수 외부에서 사용할 수있게 될 때 형성 되므로 해당 외부 함수가 반환 된 후에도 외부 함수의 변수, 함수 및 매개 변수에 대한 액세스를 유지합니다.
Tim Down

"(function () {..."을 "var func = function () {...}; func ();"로 변경하십시오. 거기, 클로저.
spoulson

이 일을하고 싶지는 않지만 ... 아직 폐쇄는 없습니다. 외부 기능 외부에서 내부 기능이 만들어지지 않습니다. 예제에서 클로저를 만드는 쉬운 방법은 다음과 같이 경고하는 함수를 반환하는 것입니다. var f = (function () {var i = 99; return function () {alert (i);};}) (); 에프();
Tim Down

지적한 점. 구현의 세부 사항에 달려 있습니다.
spoulson

2

그들은 종종 jQuery 플러그인에서 사용됩니다. 에 설명 된대로jQuery Plugins Authoring Guide 내부 { }에 선언 된 모든 변수 는 비공개이며 더 나은 캡슐화를 허용하는 외부에 보이지 않습니다.


3
{}자체적으로 JavaScript에서 새 범위를 만들지 마십시오. 범위는 함수 선언에 의해 생성됩니다.
Annabelle

2

다른 사람들이 말했듯이 둘 다 즉시 호출되는 익명 함수를 정의합니다. 일반적으로 클래스에 대한 정적 전용 범위를 만들기 위해이 구조에서 JavaScript 클래스 선언을 래핑합니다. 그런 다음 상수 데이터, 정적 메서드, 이벤트 처리기 또는 해당 범위에있는 다른 모든 항목을 배치 할 수 있으며 클래스의 인스턴스에만 표시됩니다.

// Declare a namespace object.
window.MyLibrary = {};

// Wrap class declaration to create a private static scope.
(function() {
  var incrementingID = 0;

  function somePrivateStaticMethod() {
    // ...
  }

  // Declare the MyObject class under the MyLibrary namespace.
  MyLibrary.MyObject = function() {
    this.id = incrementingID++;
  };

  // ...MyObject's prototype declaration goes here, etc...
  MyLibrary.MyObject.prototype = {
    memberMethod: function() {
      // Do some stuff
      // Maybe call a static private method!
      somePrivateStaticMethod();
    }
  };
})();

이 예에서 MyObject클래스는 MyLibrary네임 스페이스에 할당 되므로 액세스 할 수 있습니다. incrementingID그리고 somePrivateStaticMethod()직접 익명 함수의 범위를 외부에서 액세스 할 수 없습니다.


2

그것은 기본적으로 네임 스페이스입니다. JavaScript 코드의 것입니다.

예를 들어, 변수 또는 함수를 거기에 배치 할 수 있으며 외부에서는 해당 범위에 존재하지 않습니다. 따라서 거기에 모든 것을 캡슐화하면 충돌에 대해 걱정할 필요가 없습니다.

()자기 호출에 마지막 수단에서. 익명 함수의 인수가 될 인수를 추가 할 수도 있습니다. 나는 자주 jQuery로 이것을하고, 왜 그런지 알 수있다.

(function($) {

    // Now I can use $, but it won't affect any other library like Prototype
})(jQuery);

Evan Trimboli 는 그의 대답 에서 나머지를 다룹니다 .


1

자체 호출 기능입니다. 쓰기의 속기

function DoSomeStuff($)
{
}

DoSomeStuff(jQuery);

1

위의 코드가하는 일은 1 번 줄에 익명 함수를 만든 다음 0 개의 인수를 사용하여 3 번 줄에서 호출하는 것입니다. 모든 함수는 해당 익명 함수 내에서만 액세스 할 수 있기 때문에 이는 해당 라이브러리 내에 정의 된 모든 함수와 변수를 효과적으로 캡슐화합니다.

이것은 좋은 방법이며, 그 이유는 변수와 함수로 전역 네임 스페이스를 오염시키지 않기위한 것입니다. 이는 사이트 전체의 다른 Javascript에 의해 방해받을 수 있습니다.

함수가 호출되는 방식을 명확히하기 위해 간단한 예를 고려하십시오.

이 한 줄의 자바 스크립트가 포함 된 경우 명시 적으로 호출하지 않고 자동으로 호출됩니다.

alert('hello');

따라서 그 아이디어를이 예제에 적용하십시오.

(function() {
    alert('hello')
    //anything I define in here is scoped to this function only
}) (); //here, the anonymous function is invoked

익명 함수가 이전 예제와 같이 호출되기 때문에 최종 결과는 비슷합니다.


Evan에게 댓글에 대한 첫 번째 질문을 참조하십시오. 감사합니다!

//here, the anonymous function is invoked간단한,하지만 나는 :) 전에 그것을 보지 못했다
스테판

1

좋은 코드 답변이 이미 취해 졌기 때문에 :) John Resig 비디오 비디오 1 , 비디오 2 (JavaScript에서 jQuery & master의 발명가) 를 보도록 제안을 던질 것 입니다.

비디오에서 제공되는 몇 가지 좋은 통찰력과 답변.

그것이 내가 당신의 질문을 보았을 때 우연히했던 일입니다.


0
function(){ // some code here }

javascript에서 익명 함수를 정의하는 방법입니다. 다른 기능의 컨텍스트에서 기능을 실행할 수있는 기능을 제공 할 수 있습니다 (그렇지 않으면 해당 기능이 없을 수 있음).

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