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


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.