자바 스크립트에서 자체 실행 함수의 목적은 무엇입니까?


427

자바 스크립트에서 언제 이것을 사용하고 싶습니까?

(function(){
    //Bunch of code...
})();

이 위에 :

//Bunch of code...

3
또한 ( 기술적 인 ) 설명 과 여기를 살펴보십시오 . 구문 은 괄호가 필요한 이유 와 필요한 위치를 참조하십시오 .
— Bergi


세미콜론 바로 앞에 마지막 두 개의 괄호가있는 이유는 무엇입니까?
— johnny

3
@johnny 마지막 두 괄호 앞의 부분은 (익명) 함수를 선언합니다. 이 두 괄호는 함수를 호출합니다.
— Ej.

7
"즉시 호출 된 함수 표현식"또는 IIFE가 더 나은 이름 입니다.
— Flimm

답변:


404

가변 범위 지정에 관한 것입니다. 자체 실행 기능에 선언 된 변수는 기본적으로 자체 실행 기능 내에서 코드를 작성할 때만 사용할 수 있습니다. 이를 통해 다른 JavaScript 코드 블록에서 변수의 이름을 지정하는 방법에 관계없이 코드를 작성할 수 있습니다.

예를 들어 Alexander 의 의견에서 언급했듯이 :

(function() {
  var foo = 3;
  console.log(foo);
})();

console.log(foo);

정의되지 않았 으므로 먼저 로그 3에 기록한 후 다음에 오류를 발생시킵니다 .console.logfoo


7
또한 Netflix 엔지니어를 포함한 많은 사람들의 이익을 위해 : 그것은 단지 기능입니다. 폐쇄 자체를 나타내는 것은 아닙니다. 때로는 자동 호출자가 깔끔한 작업을 수행하기 위해 클로저 관련 시나리오와 함께 사용되지만 가비지 수집되고 비 폐쇄 언어로 전달되는 참조를 보유하고 있지 않은 항목은 표시되지 않습니다. 클로저와 함께하는 괴물.
— Erik Reppen

2
그래서 이것은 주로 폐쇄와 함께 사용됩니까?
— Pir Abdul

@AlexanderBird, 당신이 없이는 할 꽤 괜찮 ... 경우 var이 같은 : ...function(){ foo=3;}? 전역 변수를 설정했을까요?
— T.Todua

2
@AlexanderBird하지만 이미 함수 내부의 지역 변수에서 발생 : function(){ var foo = 3; alert(foo); }; alert(foo);그래서 난 아직도 이해가 안가
— 주앙 멘텔 페레이라

아, 알다시피, 당신은 한 번에 세 가지 기능을 모두 달성합니다. 1) 선언 만하면 기능을 실행합니다. 2) 모든 기능으로 변수 범위는 로컬입니다. 3) 기능은 익명의 주요 범위 오염되지 수 있습니다
— 주앙 멘텔 페레이라

94

단순합니다. 매우 평범한 모습, 거의 위안 :

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

그러나 고급 문자를 기본 레벨 표현으로 변환하는 정말 편리한 자바 스크립트 라이브러리를 페이지에 포함 시키면 어떻게됩니까?

무엇을 기다립니다?

누군가가 어떤 종류의 악센트가있는 문자를 입력하면 내 프로그램에서 '영어'문자 AZ 만 원합니까? 음 ... 스페인어 'ñ'과 프랑스어 'é'문자는 'n'과 'e'의 기본 문자로 변환 될 수 있습니다.

그래서 좋은 사람이 내 사이트에 포함시킬 수있는 포괄적 인 문자 변환기를 작성했습니다 ... 포함합니다.

한 가지 문제 : 내 함수와 같은 '이름'이라는 함수가 있습니다.

이것이 충돌이라고합니다. 같은 범위 에서 선언 된 두 함수가 있습니다 에서 같은 이름으로 있습니다. 우리는 이것을 피하고 싶습니다.

그래서 우리는 어떻게 든 코드의 범위를 정해야합니다.

자바 스크립트에서 코드를 범위를 지정하는 유일한 방법은 함수로 코드를 래핑하는 것입니다.

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

문제가 해결 될 수도 있습니다. 이제 모든 것이 동봉되었으며 개폐 중괄호 내에서만 접근 할 수 있습니다.

우리는 함수에 함수가 있습니다 ...보기에는 이상하지만 완전히 합법적입니다.

단 하나의 문제. 코드가 작동하지 않습니다. userName 변수는 콘솔에 에코되지 않습니다!

기존 코드 블록 뒤에 함수에 대한 호출을 추가하여이 문제를 해결할 수 있습니다.

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

main();

또는 전에!

main();

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

부차적 인 우려 : 'main'이라는 이름이 아직 사용되지 않았을 가능성은 무엇입니까? ... 매우 슬림합니다.

더 많은 범위가 필요합니다. 그리고 main () 함수를 자동으로 실행하는 방법.

이제 자동 실행 기능 (또는 자체 실행, 자체 실행 등)에 대해 살펴 보겠습니다.

((){})();

구문은 죄로 어색합니다. 그러나 작동합니다.

함수 정의를 괄호로 묶고 매개 변수 목록 (다른 세트 또는 괄호!)을 포함하면 함수 호출 역할을합니다 .

자체 실행 구문을 사용하여 코드를 다시 살펴 보겠습니다.

(function main() {
  var userName = "Sean";

    console.log(name());

    function name() {
      return userName;
    }
  }
)();

따라서 여러분이 읽은 대부분의 자습서에서 이제 '익명 자체 실행'이라는 용어 또는 이와 유사한 용어가 적용됩니다.

수년간의 전문적인 개발 끝에, 디버깅 목적으로 작성한 모든 함수의 이름을 지정할 것을 강력히 권합니다 .

문제가 발생하면 브라우저에서 역 추적을 확인하게됩니다. 스택 추적의 항목 이름이 있으면 코드 문제를 좁히는 것이 항상 더 쉽습니다!

엄청나게 긴 바람과 나는 그것이 도움이되기를 바랍니다!


2
감사합니다 :) 나는 개인 정보 보호 측면에서 정상적인 기능과 관련하여 IIFE의 장점을 이해하려고 노력하면서 인터넷을 계속 탐색하고 있었고 귀하의 답변은 단순히 최고입니다. 모든 사람들은 가장 큰 장점 중 하나는 IIFE 내부의 변수와 함수는 정상적인 함수가 정확히 같은 것을 줄 때 '마지막'으로 비공개라는 것입니다. 마지막으로 나는 당신의 설명 과정을 통해 그것을 얻었다 고 생각합니다. IIFE는 결국 기능이지만 이제는 왜 사용 해야하는지 이해합니다. 다시 감사합니다!
— viery365

시간을내어 설명해 주셔서 감사합니다.
— MSC

좋은 대답입니다. 그래도 마지막 요점에 대한 질문이 있습니다-모든 함수의 이름을 지정할 것을 권장 할 때 자체 실행 함수를 사용하여 그렇게 할 수있는 방법이 있거나 모든 사람이 함수의 이름을 지정한 다음 호출한다고 제안합니까? 편집 아, 알겠습니다. 이것은 이미 명명되었습니다. 어. 명명 된 자체 실행 기능의 사용을 정당화하고 있음을 지적 할 수 있습니다.
— FireSBurnsmuP

그럼 내 친구, 이것은 내가 찾던 해답:)
— 주앙 멘텔 페레이라

이것은 내가 찾은 대답이 아니라 허용 된 것으로 표시된 대답이 아닙니다. 나는 바로 대해 아니라고 말하는 건가요 변수 이름 충돌하지만 관한 함수 이름 충돌? 일반 비 ife 함수의 변수도 로컬 범위이며 전역 변수와 충돌하지 않습니까?
— Kumar Manish

32

자체 호출 (자동 호출이라고도 함)은 함수가 정의에 따라 즉시 실행될 때입니다. 이것은 핵심 패턴이며 JavaScript 개발의 다른 많은 패턴의 기초가됩니다.

나는 큰 팬입니다 :)

  • 코드를 최소한으로 유지합니다
  • 프레젠테이션에서 행동을 분리시킵니다.
  • 이름 충돌을 방지하는 클로저를 제공합니다.

엄청나게 – (왜 좋은 말을해야합니까?)

  • 함수를 한 번에 정의하고 실행하는 것입니다.
  • 자체 실행 함수가 값을 반환하고 함수를 매개 변수로 다른 함수에 전달하도록 할 수 있습니다.
  • 캡슐화에 좋습니다.
  • 블록 범위 지정에도 좋습니다.
  • 예, 모든 .js 파일을 자체 실행 기능으로 묶을 수 있으며 전역 네임 스페이스 오염을 방지 할 수 있습니다. ;)

여기 더 .


43
포인트 1. 어떻게? 포인트 2. 그것은 완전히 다른 모범 사례에서 나온 것입니다. 포인트 3. 어떤 기능이 작동하지 않습니까? 4,5,6,7. 관련성? 8. 1/8은 나쁘지 않습니다.
— Erik Reppen

2
7 년 늦었지만 포인트 1의 경우 코드를 전혀 줄이지 않으며 실제로 함수를 만드는 데 최소 두 줄의 코드가 추가됩니다.
— YungGun

1
여기서는 "이름 충돌을 방지하는 클로저를 제공합니다"라는 것만 언급하면됩니다. 아마도 당신은 당신의 대답을 단순화 할 수 있습니까?
— pcarvalho

19

네임 스페이스. JavaScript의 범위는 기능 수준입니다.


7
공감 범위에 이름 공간을 사용했기 때문에 공감대 가 여전히오고 있습니다 . 이것은 정의의 문제입니다. 예를 들어 Wikipedia : 컴퓨터 과학의 네임 스페이스 (이름 범위라고도 함)는 고유 식별자 또는 기호 (예 : 이름)의 논리적 그룹을 유지하기 위해 생성 된 추상 컨테이너 또는 환경입니다. 및 네임 스페이스 식별자는 이름 컨텍스트 (컴퓨터 과학의 범위)을 제공 할 수 있으며, 용어는 종종 같은 의미로 사용됩니다.
— Christoph

5
Javascript의 함수 레벨 범위는 변수 이름이있는 공간 인 네임 스페이스를 제공합니다 . 그것이 네임 스페이스 식별자와 관련이없는 익명의 것은 무의미합니다.
— Christoph

12

나는 암시 적 세계를 언급 한 답을 전혀 믿을 수 없다.

(function(){})()구조는, 나에게 어느 것이 더 큰 문제입니다, 묵시적 전역에 대해 보호하지 않습니다 참조 http://yuiblog.com/blog/2006/06/01/global-domination/

기본적으로 함수 블록은 정의한 모든 종속 "전역 변수"가 프로그램에 국한되어 있는지 확인하지만 암시 적 전역을 정의하는 것을 방지하지는 않습니다. JSHint 은이 동작을 방지하는 방법에 대한 권장 사항을 제공 할 수 있습니다.

간결한 var App = {}구문은 비슷한 수준의 보호를 제공하며 '공개'페이지에있을 때 기능 블록에 래핑 될 수 있습니다. ( 이 구문을 사용하는 라이브러리의 실제 예는 Ember.js 또는 SproutCore 를 참조하십시오 )

지금까지로 private특성 가고, 그들은 종류의 공용 프레임 워크 또는 라이브러리를 생성하지 않는 과대 평가의, 그러나 당신이 그들을 구현해야하는 경우, 더글러스 크록 포드는 좋은 아이디어를 가지고있다.


8
엄격한 모드는 암시 적 글로벌로부터 보호합니다. 자동 호출자와 함께 당신을 커버 할 것입니다. 나는 개인 재산에 대한 후 팔라를 이해하지 못했습니다. func 생성자 안에 vars를 선언하십시오. 끝난. 'new'키워드를 잊어 버린다는 생각이 밤에 계속 들리면 팩토리 함수를 작성하십시오. 다시 완료
— Erik Reppen

8

나는 모든 답변을 읽었으며 여기에 매우 중요한 것이 빠져 있습니다 . 자체 실행 익명 함수가 필요한 이유 또는 " IIFE (Inmediately Invoked Function Expression) "가 더 나은 이유는 다음 두 가지가 있습니다 .

  1. 더 나은 네임 스페이스 관리 (네임 스페이스 오염 방지-> JS 모듈)
  2. 폐쇄 (OOP에서 알려진 것처럼 개인 클래스 구성원 시뮬레이션)

첫 번째는 매우 잘 설명되었습니다. 두 번째 예는 다음 예제를 연구하십시오.

var MyClosureObject = (function (){
  var MyName = 'Michael Jackson RIP';
  return {
    getMyName: function () { return MyName;},
    setMyName: function (name) { MyName = name}
  }
}());

주의 1 : 우리는 함수를 할당하지 않고 MyClosureObject, 그 함수를 호출 한 결과를 더 많이 제공 합니다 . ()마지막 줄에 유의하십시오 .

주의 2 : Javascript의 함수에 대해 추가로 알아야 할 것은 내부 함수가 함수 의 매개 변수 및 변수 에 액세스 할 수 있다는 것 입니다.

몇 가지 실험을 해보자.

내가 얻을 수있는 MyName사용 getMyName하고 그것을 작동합니다 :

 console.log(MyClosureObject.getMyName()); 
 // Michael Jackson RIP

다음과 같은 독창적 인 접근 방식이 작동하지 않습니다.

console.log(MyClosureObject.MyName); 
// undefined

그러나 다른 이름을 설정하고 예상 결과를 얻을 수 있습니다.

MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName()); 
// George Michael RIP

편집 : 위의 예 MyClosureObject에서 new접두사 없이 사용되도록 설계되었으므로 일반적으로 대문자로 사용해서는 안됩니다.


7

매개 변수가 있고 "Bunch of code"가 함수를 반환합니까?

var a = function(x) { return function() { document.write(x); } }(something);

폐쇄. 에 something지정된 함수가 사용하는 값입니다 a. something다양한 값 (for loop)을 가질 수 있으며 새로운 기능을 가질 때마다.


+1; 나는 명시 적 선호 var x = something;를 통해 외부 함수를 x하지만 매개 변수로 : IMO는이 방법은 ... 더 읽기입니다
— 크리스토프

@Christoph : 함수가 생성 된 후 "무언가"의 값이 변하면 생성 당시의 값이 아닌 새로운 값을 사용합니다.
— stesch February

@ stesch : 어디서 얻었습니까? 내가 아는 한, 그렇지 않습니다. JS에서 실제 참조를 얻는 유일한 방법은 arguments-object를 사용하는 것이지만 모든 브라우저에서 작동하지는 않습니다.
— Christoph

@Christoph : "자바 스크립트 : 좋은 부품", 더글러스 크록 포드 (라일리)
— stesch

@stesch : 설명하는 방식으로 작동하지 않습니다. 변수를 삭제 x하고 어휘 범위에 직접 의존 하는 경우 새 값이 사용됩니다 document.write(something).
— Christoph

6

스코프 격리. 따라서 함수 선언 내부의 변수는 외부 네임 스페이스를 오염시키지 않습니다.

물론 JS 구현의 절반에서 어쨌든 그들은 구현할 것입니다.


4
그것들은 어떤 구현입니까?
— Matthew Crumley

1
엄격 모드로 작성되지 않고 전역 선언을 포함하는 암시 적 var 선언을 포함하는 구현.
— Erik Reppen

5

다음은 자체 호출 익명 함수가 유용한 방법에 대한 확실한 예입니다.

for( var i = 0; i < 10; i++ ) {
  setTimeout(function(){
    console.log(i)
  })
}

산출: 10, 10, 10, 10, 10...

for( var i = 0; i < 10; i++ ) {
  (function(num){
    setTimeout(function(){
      console.log(num)
    })
  })(i)
}

산출: 0, 1, 2, 3, 4...


첫 번째 코드 세트에 대해 어떻게되는지 좀 더 설명해 주시겠습니까
— radio_head

으로 let대신 var첫 번째 경우하는 것은 괜찮을 것입니다.
— Vitaly Zdanevich

3

한 가지 차이점은 함수에서 선언 한 변수가 로컬이므로 함수를 종료하면 사라지고 다른 코드의 다른 변수와 충돌하지 않는다는 것입니다.


1

Javascript의 함수는 일급 객체이므로이를 정의하여 C ++ 또는 C #과 같은 "클래스"를 효과적으로 정의합니다.

이 함수는 지역 변수를 정의하고 그 안에 함수를 가질 수 있습니다. 내부 함수 (실제로 인스턴스 메소드)는 로컬 변수 (실제로 인스턴스 변수)에 액세스 할 수 있지만 나머지 스크립트와는 분리됩니다.


1

자바 스크립트에서 자체 호출 함수 :

자체 호출 표현식은 호출되지 않고 자동으로 호출 (시작)됩니다. 자체 호출 표현식은 작성된 직후에 호출됩니다. 이것은 기본적으로 이름 충돌을 피하고 캡슐화를 달성하는 데 사용됩니다. 변수 또는 선언 된 객체는이 함수 외부에서 액세스 할 수 없습니다. 최소화 (filename.min)의 문제를 피하려면 항상 자체 실행 기능을 사용하십시오.


1

자체 실행 기능은 변수의 범위를 관리하는 데 사용됩니다.

변수의 범위는 변수가 정의 된 프로그램의 영역입니다.

전역 변수에는 전역 범위가 있습니다. JavaScript 코드의 어느 곳에서나 정의되며 함수 내에서도 스크립트 내 어디에서나 액세스 할 수 있습니다. 반면, 함수 내에서 선언 된 변수는 함수 본문 내에서만 정의됩니다. 그것들은 지역 변수이며 지역 범위가 있으며 그 기능 내에서만 액세스 할 수 있습니다. 함수 매개 변수는 로컬 변수로 계산되며 함수 본문 내에서만 정의됩니다.

아래에 표시된 것처럼 함수 내에서 전역 변수에 액세스 할 수 있으며 함수 본문 내에서 로컬 변수가 이름이 같은 전역 변수보다 우선합니다.

var globalvar = "globalvar"; // this var can be accessed anywhere within the script

function scope() {
    alert(globalvar);
    localvar = "localvar" //can only be accessed within the function scope
}

scope(); 

따라서 기본적으로 자체 실행 기능을 사용하면 변수가 다른 JavaScript 코드 블록에서 명명되는 방식에 관계없이 코드를 작성할 수 있습니다.


1
(function(){
    var foo = {
        name: 'bob'
    };
    console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error

실제로, 위 함수는 이름이없는 함수 표현식으로 취급됩니다.

닫고 괄호로 함수를 감싸는 주요 목적은 전역 공간을 오염시키는 것을 피하는 것입니다.

함수 표현식 내부의 변수와 함수는 비공개가되었습니다 (즉, 함수 외부에서는 사용할 수 없습니다).


1

짧은 대답은 글로벌 (또는 그 이상) 범위의 오염을 방지하는 것입니다.

IIFE (즉시 호출 함수 표현식)는 스크립트를 플러그인, 애드온, 사용자 스크립트 또는 다른 사람의 스크립트와 함께 작동 할 것으로 예상되는 스크립트로 작성 하는 가장 좋은 방법 입니다 . 이렇게하면 정의한 변수가 다른 스크립트에 바람직하지 않은 영향을주지 않습니다.

이것은 IIFE 표현을 작성하는 다른 방법입니다. 개인적으로 다음 방법을 선호합니다.

void function() {
  console.log('boo!');
  // expected output: "boo!"
}();

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void

위의 예에서 IIFE가 효율성과 성능에 영향을 줄 수 있다는 것은 매우 분명합니다. 한 번만 실행될 것으로 예상되는 기능이 한 번만 실행 된 다음 void로 덤프되기 때문 입니다. 이는 함수 또는 메소드 선언이 메모리에 남아 있지 않음을 의미합니다.


니스, 나는 그 void전에 그 사용법을 보지 못했습니다 . 나는 그것을 좋아한다.
— Ej.

1

먼저 방문해야 MDN 인생을 , 이것에 대해 이제 몇 가지 포인트를

  • 이것은 즉시 호출 된 함수 표현식입니다. 입니다. 따라서 자바 스크립트 파일이 HTML에서 호출되면 즉시이 함수가 호출되었습니다.
  • 이를 통해 IIFE 관용구 내의 변수에 액세스하고 전역 범위를 오염시키는 것을 방지 할 수 있습니다.

0

이 질문에 대한 답변이 모두 준비된 것처럼 보이지만 어쨌든 입력 내용을 게시하겠습니다.

자체 실행 기능을 언제 좋아하는지 알고 있습니다.

var myObject = {
    childObject: new function(){
        // bunch of code
    },
    objVar1: <value>,
    objVar2: <value>
}

이 함수를 사용하면 추가 코드를 사용하여 일반적으로 사용되는 변수 설정 또는 수학 방정식 실행과 같은 더 깨끗한 코드의 childObjects 속성 및 속성을 정의 할 수 있습니다. 오! 또는 오류 점검. 중첩 된 객체 인스턴스화 구문으로 제한되는 것과는 대조적으로 ...

object: {
    childObject: {
        childObject: {<value>, <value>, <value>}
    }, 
    objVar1: <value>,
    objVar2: <value>
}

일반적으로 코딩은 똑같은 일을 많이하는 모호한 방법이 많으므로 "왜 귀찮게합니까?" 그러나 더 이상 기본 / 핵심 교장에만 의존 할 수없는 새로운 상황이 계속 나타납니다.


0

간단한 질문이 있습니다 : "자바 스크립트에서 언제 이것을 사용하겠습니까 : ..."

@ken_browning 및 @sean_holding의 답변이 마음에 들지만 여기에 언급되지 않은 다른 유스 케이스가 있습니다.

let red_tree = new Node(10);

(async function () {
    for (let i = 0; i < 1000; i++) {
        await red_tree.insert(i);
    }
})();

console.log('----->red_tree.printInOrder():', red_tree.printInOrder());

여기서 Node.insert는 일부 비동기 조치입니다.

내 함수 선언에서 async 키워드없이 await를 호출 할 수 없으며 나중에 사용하기 위해 명명 된 함수가 필요하지 않지만 삽입 호출을 기다려야하거나 다른 풍부한 기능이 필요합니다 (누군가 아는가?) .


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