[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
.
- developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Function_constructor_vs._function_declaration_vs._function_expression
- 자바 스크립트 : 문장과 표현식의 차이점은 무엇입니까?
- 표현 대 진술
범위 이해하기
한 가지 궁금한 점은 “함수 내에 변수를 ‘적절하게’정의하지 않으면 어떻게됩니까? 즉, 간단한 대입을 수행합니까?”
(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
.
자원
- youtu.be/i_qE1iAmjFg?t=2m15s-Paul Irish는 IIFE를 최소 2:15에 선물합니다. 이것을보십시오!
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ 함수
- 책 : Javascript, 좋은 부분 -강력 추천
- youtu.be/i_qE1iAmjFg?t=4m36s-Paul Irish는 4:36에 모듈 패턴을 나타냅니다.
다음 단계
이 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);
답변
- 같은 창에서 다른 방법 / 라이브러리와 충돌을 피하려면
- 글로벌 범위를 피하고 로컬 범위로 설정하십시오.
- 디버깅 속도를 높이려면 (로컬 범위)
- JavaScript에는 기능 범위 만 있으므로 코드 컴파일에도 도움이됩니다.