[javascript] “(function () {…}) ()”와 같은 익명 함수로 전체 Javascript 파일을 래핑하는 목적은 무엇입니까?

최근에 많은 Javascript를 읽었으며 가져올 전체 .js 파일에서 전체 파일이 다음과 같이 래핑되어 있음을 알았습니다.

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

간단한 생성자 함수 세트가 아닌 이것을 수행하는 이유는 무엇입니까?



답변

일반적으로 네임 스페이스 (나중에 참조)에 있으며 멤버 함수 및 / 또는 변수의 가시성을 제어합니다. 그것을 객체 정의처럼 생각하십시오. 이에 대한 기술적 이름은 IIFE (Inmediately Invoked Function Expression )입니다. jQuery 플러그인은 일반적으로 다음과 같이 작성됩니다.

자바 스크립트에서는 함수를 중첩 할 수 있습니다. 따라서 다음은 합법적입니다.

function outerFunction() {
   function innerFunction() {
      // code
   }
}

이제 전화를 걸 수 outerFunction()있지만의 가시성은 innerFunction()의 범위로 제한 outerFunction()됩니다 outerFunction(). 기본적으로 Javascript의 변수와 동일한 원칙을 따릅니다.

var globalVariable;

function someFunction() {
   var localVariable;
}

해당 :

function globalFunction() {

   var localFunction1 = function() {
       //I'm anonymous! But localFunction1 is a reference to me!
   };

   function localFunction2() {
      //I'm named!
   }
}

위 시나리오에서는 globalFunction()어디서나 전화 를 걸 수 있지만 localFunction1또는 전화를 걸 수는 없습니다 localFunction2.

당신이 쓸 때하고있는 일은 (function() { ... })()첫 번째 괄호 안의 코드를 함수 리터럴로 만드는 것입니다 (전체 “객체”가 실제로 함수임을 의미합니다). 그 후에 ()방금 정의한 함수 (final )를 자체 호출합니다 . 앞에서 언급했듯이 이것의 가장 큰 장점은 개인 메소드 / 함수 및 속성을 가질 수 있다는 것입니다.

(function() {
   var private_var;

   function private_function() {
     //code
   }
})();

첫 번째 예에서는 globalFunction이름 으로 명시 적으로 호출 하여 실행합니다. 즉, 당신은 globalFunction()그것을 실행하려고 할 것입니다. 그러나 위 예제에서 함수를 정의하는 것이 아닙니다. 한 번에 정의 하고 호출합니다. 즉, JavaScript 파일이로드되면 즉시 실행됩니다. 물론, 당신은 할 수 있습니다 :

function globalFunction() {
    // code
}
globalFunction();

IIFE를 사용할 때 전역 범위를 오염시키지 마십시오 (결과적으로 이름이 없기 때문에 함수를 여러 번 호출 할 수 없음을 의미 함). 이 함수는 실제로 문제가되지 않는 경우에만 실행되도록되어 있습니다).

IIFE의 깔끔한 점은 내부를 정의하고 원하는 부분 만 외부 세계에 노출시킬 수 있다는 것입니다 (이름 공간 지정의 예를 통해 기본적으로 자체 라이브러리 / 플러그인을 만들 수 있음).

var myPlugin = (function() {
 var private_var;

 function private_function() {
 }

 return {
    public_function1: function() {
    },
    public_function2: function() {
    }
 }
})()

이제 전화 myPlugin.public_function1()를 걸 수 있지만 액세스 할 수 없습니다 private_function()! 클래스 정의와 매우 비슷합니다. 이것을 더 잘 이해하려면 다음 링크를 참조하십시오.

편집하다

나는 언급하는 것을 잊었다. 마지막으로 (), 당신은 당신이 원하는 모든 것을 전달할 수 있습니다. 당신의 jQuery 플러그인을 만들 때 예를 들어, 전달 jQuery또는 $과 같이 :

(function(jQ) { ... code ... })(jQuery) 

그래서 여기서하고있는 것은 하나의 매개 변수 ( jQ로컬 변수 라고 하며 해당 함수 에만 알려진 함수)를 취하는 함수를 정의하는 것입니다 . 그럼 당신은있는 거 자체 호출 기능 및 매개 변수 전달 (또한 jQuery,하지만 사람은 외부 세계와 실제 jQuery를 자체에 대한 참조에서이다). 이 작업을 수행 할 필요는 없지만 몇 가지 장점이 있습니다.

  • 전역 매개 변수를 재정의하고 로컬 범위에 적합한 이름을 지정할 수 있습니다.
  • 스코프 체인을 전역 범위로 이동하지 않고 로컬 범위에서 검색하는 것이 더 빠르기 때문에 약간의 성능 이점이 있습니다.
  • 압축에는 이점이 있습니다 (최소화).

이전에 이러한 함수가 시작시 자동으로 실행되는 방법에 대해 설명했지만 자동으로 실행되는 경우 누가 인수를 전달합니까? 이 기법은 필요한 모든 매개 변수가 이미 전역 변수로 정의되어 있다고 가정합니다. 따라서 jQuery가 전역 변수로 아직 정의되지 않은 경우이 예제는 작동하지 않습니다. 짐작할 수 있듯이 jquery.js가 초기화하는 동안 수행하는 한 가지 작업은 ‘jQuery’전역 변수와 더 유명한 ‘$’전역 변수를 정의하는 것입니다.이 변수는 jQuery가 포함 된 후이 코드가 작동하도록합니다.


답변

한마디로

요약

가장 간단한 형태로,이 기술은 코드를 함수 범위 안에 넣는 것을 목표로 합니다.

다음과 같은 가능성을 줄이는 데 도움이됩니다.

  • 다른 응용 프로그램 / 라이브러리와 충돌
  • 우수한 (전 세계적으로 가장 가능성이 높은) 오염

그것은 하지 않는 문서가 준비되면 감지 – 그것은 어떤 종류의하지 document.onload않고window.onload

일반적으로 Immediately Invoked Function Expression (IIFE)또는 로 알려져 있습니다 Self Executing Anonymous Function.

코드 설명

var someFunction = function(){ console.log('wagwan!'); };

(function() {                   /* function scope starts here */
  console.log('start of IIFE');

  var myNumber = 4;             /* number variable declaration */
  var myFunction = function(){  /* function variable declaration */
    console.log('formidable!');
  };
  var myObject = {              /* object variable declaration */
    anotherNumber : 1001,
    anotherFunc : function(){ console.log('formidable!'); }
  };
  console.log('end of IIFE');
})();                           /* function scope ends */

someFunction();            // reachable, hence works: see in the console
myFunction();              // unreachable, will throw an error, see in the console
myObject.anotherFunc();    // unreachable, will throw an error, see in the console

위의 예에서 함수에 정의 된 (즉,을 사용하여 선언 된) 변수 var는 “비공개”이고 함수 범위 내에서만 액세스 할 수 있습니다 (Vivin Paliath가 말한 것처럼). 다시 말해, 이러한 변수는 함수 외부에서 보이거나 도달 할 수 없습니다. 라이브 데모를 참조하십시오 .

Javascript에는 기능 범위가 있습니다. “함수에 정의 된 매개 변수와 변수는 함수 외부에 표시되지 않으며, 함수 내에서 정의 된 변수는 함수 내 어디에서나 볼 수 있습니다.” ( “자바 스크립트 : 좋은 부분”에서).


자세한 내용은

대체 코드

결국, 이전에 게시 된 코드는 다음과 같이 수행 될 수 있습니다.

var someFunction = function(){ console.log('wagwan!'); };

var myMainFunction = function() {
  console.log('start of IIFE');

  var myNumber = 4;
  var myFunction = function(){ console.log('formidable!'); };
  var myObject = {
    anotherNumber : 1001,
    anotherFunc : function(){ console.log('formidable!'); }
  };
  console.log('end of IIFE');
};

myMainFunction();          // I CALL "myMainFunction" FUNCTION HERE
someFunction();            // reachable, hence works: see in the console
myFunction();              // unreachable, will throw an error, see in the console
myObject.anotherFunc();    // unreachable, will throw an error, see in the console

라이브 데모를 참조하십시오 .


뿌리

반복 1

언젠가 누군가는 “myMainFunction”이라는 이름을 피하는 방법이 있어야한다고 생각했을 것입니다. 왜냐하면 우리가 원하는 것은 바로 그것을 실행하는 것이기 때문입니다. “

기본으로 돌아 가면 다음을 알 수 있습니다.

  • expression: 가치를 평가하는 것. 즉3+11/x
  • statement: 코드 행으로 무언가를 수행하지만 값으로 평가 되지 않습니다 . 즉if(){}

마찬가지로 함수 표현식은 값으로 평가됩니다. 그리고 하나의 결과 (나는 가정합니까?)는 즉시 호출 할 수 있다는 것입니다.

 var italianSayinSomething = function(){ console.log('mamamia!'); }();

보다 복잡한 예는 다음과 같습니다.

var someFunction = function(){ console.log('wagwan!'); };

var myMainFunction = function() {
  console.log('start of IIFE');

  var myNumber = 4;
  var myFunction = function(){ console.log('formidable!'); };
  var myObject = {
    anotherNumber : 1001,
    anotherFunc : function(){ console.log('formidable!'); }
  };
  console.log('end of IIFE');
}();

someFunction();            // reachable, hence works: see in the console
myFunction();              // unreachable, will throw an error, see in the console
myObject.anotherFunc();    // unreachable, will throw an error, see in the console

라이브 데모를 참조하십시오 .

반복 2

다음 단계는 ” var myMainFunction =우리가 그것을 사용하지 않으면 왜 !”라는 생각입니다.

대답은 간단합니다. 아래와 같이 제거해보십시오.

 function(){ console.log('mamamia!'); }();

라이브 데모를 참조하십시오 .

“함수 선언은 호출 할 수 없으므로 “작동하지 않습니다 .

비결은 제거함으로써 함수 표현식함수 선언 으로 var myMainFunction =변환 했다는 것 입니다. 이에 대한 자세한 내용은 “리소스”링크를 참조하십시오.

다음 질문은 “왜 다른 식으로 함수 표현식으로 유지할 수 var myMainFunction =없습니까?

대답은 “당신이 할 수있는 것”이며 실제로 당신이 이것을 할 수있는 많은 방법이 있습니다 : +, a !, a -또는 아마도 한 쌍의 괄호로 묶는 것 (지금은 컨벤션에 의해 이루어짐), 그리고 나는 더 믿습니다. 예를 들어 :

 (function(){ console.log('mamamia!'); })(); // live demo: jsbin.com/zokuwodoco/1/edit?js,console.

또는

 +function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wuwipiyazi/1/edit?js,console

또는

 -function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wejupaheva/1/edit?js,console

따라서 일단 “대체 코드”에 해당 수정 사항이 추가되면 “코드 설명”예제에서 사용한 코드와 정확히 동일한 코드로 돌아갑니다.

var someFunction = function(){ console.log('wagwan!'); };

(function() {
  console.log('start of IIFE');

  var myNumber = 4;
  var myFunction = function(){ console.log('formidable!'); };
  var myObject = {
    anotherNumber : 1001,
    anotherFunc : function(){ console.log('formidable!'); }
  };
  console.log('end of IIFE');
})();

someFunction();            // reachable, hence works: see in the console
myFunction();              // unreachable, will throw an error, see in the console
myObject.anotherFunc();    // unreachable, will throw an error, see in the console

다음에 대해 자세히 알아보십시오 Expressions vs Statements.


범위 이해하기

한 가지 궁금한 점은 “함수 내에 변수를 ‘적절하게’정의하지 않으면 어떻게됩니까? 즉, 간단한 대입을 수행합니까?”

(function() {
  var myNumber = 4;             /* number variable declaration */
  var myFunction = function(){  /* function variable declaration */
    console.log('formidable!');
  };
  var myObject = {              /* object variable declaration */
    anotherNumber : 1001,
    anotherFunc : function(){ console.log('formidable!'); }
  };
  myOtherFunction = function(){  /* oops, an assignment instead of a declaration */
    console.log('haha. got ya!');
  };
})();
myOtherFunction();         // reachable, hence works: see in the console
window.myOtherFunction();  // works in the browser, myOtherFunction is then in the global scope
myFunction();              // unreachable, will throw an error, see in the console

라이브 데모를 참조하십시오 .

기본적으로 현재 범위에서 선언되지 않은 변수에 값이 할당 된 경우 “변수를 찾거나 전역 범위에 도달 할 때까지 범위 체인을 조회합니다 (이 시점에서 변수가 생성됩니다)”.

브라우저 환경 (nodejs와 같은 서버 환경)에서 전역 범위는 window객체에 의해 정의됩니다 . 따라서 우리는 할 수 있습니다 window.myOtherFunction().

이 주제에 대한 나의 “우수 사례”팁 은 숫자, 객체 또는 함수이든 전역 범위에 있을 때든 무엇이든 정의 할 때 항상 사용 var하는 것 입니다. 이렇게하면 코드가 훨씬 간단 해집니다.

노트 :

  • javascript 에는 (업데이트 : ES6에 추가 된 블록 범위 로컬 변수) 가 없습니다 .block scope
  • 자바 스크립트에는 function scope& 만 있습니다 global scope( window브라우저 환경에서 범위)

다음에 대해 자세히 알아보십시오 Javascript Scopes.


자원


다음 단계

IIFE개념 을 얻으면 module pattern이 IIFE 패턴을 활용하여 일반적으로 수행됩니다. 재미있게 보내세요 🙂


답변

브라우저의 Javascript에는 실제로 함수 범위와 전역 범위의 두 가지 유효 범위 만 있습니다.

변수가 함수 범위에 없으면 전역 범위에 있습니다. 전역 변수는 일반적으로 나쁘기 때문에 라이브러리 변수를 자체적으로 유지하는 구조입니다.


답변

이를 폐쇄라고합니다. 기본적으로 함수 내부의 코드를 밀봉하여 다른 라이브러리가 방해하지 않도록합니다. 컴파일 된 언어로 네임 스페이스를 만드는 것과 비슷합니다.

예. 내가 쓴다고 가정 해보십시오.

(function() {

    var x = 2;

    // do stuff with x

})();

이제 다른 라이브러리는 x내 라이브러리에서 사용하기 위해 만든 변수에 액세스 할 수 없습니다 .


답변

함수 클로저를 다음과 같이 사용할 수 있습니다 일부 html5 객체에 대한 브라우저 지원을 결정하는이 방법 에서처럼 더 큰 표현식의 데이터 .

   navigator.html5={
     canvas: (function(){
      var dc= document.createElement('canvas');
      if(!dc.getContext) return 0;
      var c= dc.getContext('2d');
      return typeof c.fillText== 'function'? 2: 1;
     })(),
     localStorage: (function(){
      return !!window.localStorage;
     })(),
     webworkers: (function(){
      return !!window.Worker;
     })(),
     offline: (function(){
      return !!window.applicationCache;
     })()
    }


답변

변수를 로컬로 유지하는 것 외에도 전역 변수를 사용하여 라이브러리를 작성할 때 라이브러리에서 사용할 짧은 변수 이름을 지정할 수 있습니다. jQuery를 사용하면 jQuery.noConflict ()를 사용하여 jQuery를 가리키는 $ 변수를 비활성화 할 수 있으므로 jQuery 플러그인 작성에 자주 사용됩니다. 비활성화 된 경우 코드는 여전히 $를 사용할 수 있으며 다음과 같은 경우 중단되지 않습니다.

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


답변

  1. 같은 창에서 다른 방법 / 라이브러리와 충돌을 피하려면
  2. 글로벌 범위를 피하고 로컬 범위로 설정하십시오.
  3. 디버깅 속도를 높이려면 (로컬 범위)
  4. JavaScript에는 기능 범위 만 있으므로 코드 컴파일에도 도움이됩니다.