그게 뭐야
JavaScript에서, 호출 될 때 각 함수는 새로운 실행 컨텍스트를 만듭니다. 함수에 정의 된 변수와 함수는 함수를 호출 할 때 외부가 아닌 내부적으로 액세스하는 유일한 변수이므로 함수가 제공 한 컨텍스트는 개인 변수를 생성하는 매우 간단한 방법을 제공합니다.
함수 makecounter () {var i = 0; return function () {console.log (++ i); }; } // 기억하십시오 :`counter '와`counter2`는 자체 변수가 있습니다.`i`var counter = makecounter (); counter (); // 1counter (); // 2var counder2 = makecounter (); counter2 (); // 1counter2 (); // 2i; // 참조 레터 : i는 (makecounter에서만 Exists에만 정의되지 않습니다).대부분의 경우, 여러 축적 된 값을 반환하기 위해 Make Whathing과 같은 함수가 필요하지 않을 수 있으며, 단일 값을 얻기 위해 한 번만 호출 할 수 있으며 다른 경우에는 반품 값을 명시 적으로 알 필요조차 없습니다.
그 핵심
이제 함수 foo () {} 또는 var foo = function () {}와 같은 함수를 정의하더라도 호출 할 때 foo ()와 같은 괄호 한 쌍을 추가해야합니다.
// 아래 정의 된 함수는`foo ()`, //와 같은 함수 이름 뒤에 한 쌍의 괄호를 추가하여 호출 할 수 있습니다. foo는 단지 참조 변수 var var foo = function () {/ * code */}`함수`function ()에 비해 () {/ * code */}`var foo = function () {/ * code * // 그 후 괄호? function () { / * code * /} (); // syntaxerror : 예기치 않은 토큰 (보시다시피, 버그가 여기에 갇혀 있습니다. 지구 환경이나 로컬 환경에서 이러한 기능 키워드를 만나든 기본적으로 함수를 호출하기 위해 괄호가 함수 뒤에 나타날 때, 기능 표현이 아닌 함수 선언으로 취급됩니다. 괄호에게 표현식이라고 명시 적으로 말하지 않으면 함수 선언에 이름이 필요하기 때문에 이름이없는 함수로 취급되고 오류가 발생합니다.
질문 1 : 여기서 질문을 생각할 수 있습니까? 또한 기능을 Var Foo = function () {console.log (1)} ()와 같이 직접 호출 할 수 있으며 답은 괜찮습니다.
질문 2 : 마찬가지로, 우리는 또한 질문에 대해 생각할 수 있습니다. 이와 같은 함수 선언이 그 후 괄호로 직접 호출되면 어떻게됩니까? 아래 답변을 참조하십시오.
함수, 괄호, 오류
흥미롭게도, 함수의 이름을 지정하고 그 뒤에 한 쌍의 괄호를 넣으면 같은 오류가 발생하지만 이번에는 또 다른 이유가 있습니다. 함수 표현식 이후 괄호가 배치되면, 이것이 호출 된 함수이며, 선언 후 괄호가 배치되었음을 나타냅니다. 이는 이전 함수 선언과 완전히 분리되어 있음을 의미합니다. 현재 괄호는 괄호 (작동 우선 순위를 제어하는 데 사용되는 버팀대)를 간단하게 표현하는 것입니다.
// 함수 선언은 구문 적으로 유효하지 않으며, 여전히 선언이며, 다음 괄호는 유효하지 않습니다. 괄호 안에 표현 함수 foo () {/ * code */} (); // syntaxerror를 포함해야하기 때문에 다음 괄호가 포함되어야하기 때문입니다. foo () {/ * code */} (1) // 다음과 동일하며, 함수 선언은 전혀 관계가없는 표현을 따릅니다. function foo () {/ * code */} (1);기능 표현을 즉시 실행 (IIFE)
다행스럽게도 문법 오류를 쉽게 해결할 수 있습니다. 가장 인기 있고 가장 많이 받아 들여지는 방법은 괄호 안에 함수 선언을 괄호로 래핑하여 Parser에게 함수 표현식을 표현하도록 지시하는 것입니다. JavaScript에는 괄호 안에 선언이 포함될 수 없기 때문입니다. 이로 인해 괄호가 함수를 래핑하기 위해 함수 키워드를 만나면 함수 선언 대신 함수 표현식으로 구문 분석하는 것을 알고 있습니다. 여기서 괄호가 기능을 만나면 위의 괄호와 다르다는 것을 이해하는 데주의를 기울이십시오.
익명 함수의 끝에 괄호가 나타나고 함수를 호출하려면 기능을 함수 선언으로 취급하는 것이 기본값입니다.
괄호 안에 함수를 감을 때는 함수를 선언하지 않고 기본적으로 표현식으로 함수를 구문 분석합니다.
// 두 패턴 모두 함수의 실행을 사용하여 개인 변수를 생성하기 위해 즉시 함수 표현식을 호출하는 데 사용할 수 있습니다 (function () {/ * code */} ()); // Crockford는 이것을 추천합니다. 괄호 안의 표현식은 기능을 즉시 나타냅니다 (함수 () {/ * code */}) (); 운영자는 // 함수 표현식과 함수 선언 사이에서 //를 명확하게해야한다면, 파서가 이미 표현식을 기대할 때 // 생략 될 수 있습니다 (그러나 // "중요한 노트"아래)을 참조하십시오. 가능하면, 당신은 당신의 기능 앞에서 단독 연산자를 가져 가서 바이트를 저장할 수 있습니다! function () {/ * code */} (); ~ function () {/ * code */} (); - function () {/ * code */} ();+function () {/ * code */} (); // @kuvos의 또 다른 변형이 있습니다. http://twitter.com/kuvos/status/18209252090847232new function () {/ * code */} new function () {/ * code */} () // 인수를 전달하는 경우에만 Parens 만 필요합니다.브래킷에 대한 중요한 메모
경우에 따라 추가 모호한 괄호가 함수 표현 주위에있을 때 (브래킷이 이미 표현식으로 표현되어 있기 때문에) 기능 표현을 둘러싸는 것이 필요하지 않지만, 브래킷이 함수 표현식을 호출하는 데 여전히 좋은 생각입니다.
이러한 괄호는 함수 표현식이 즉시 호출되고 변수가 함수 자체가 아니라 함수의 결과를 저장 함을 나타냅니다. 이것이 매우 긴 함수 표현식 인 경우, 기능이 호출되는지 확인하기 위해 페이지 하단으로 스크롤하지 않고도 코드를 읽는 사람들보다 시간이 절약됩니다.
일반적으로 명확하고 명확한 코드를 작성할 때 JavaScript가 오류를 던지지 않도록해야하며 다른 개발자가 WTFerror에 오류를 던지지 않도록해야합니다!
폐쇄 상태를 저장하십시오
함수가 이름으로 호출 될 때와 마찬가지로 매개 변수가 전달되고 함수 표현식이 즉시 호출되면 매개 변수가 전달됩니다. 함수 내에서 정의 된 함수는 외부 함수에 의해 전달되는 매개 변수와 변수를 사용할 수 있기 때문에 즉시 호출 된 함수 표현식은 값을 잠그고 상태를 효과적으로 저장하는 데 사용될 수 있습니다 (이 관계는 폐쇄라고합니다).
//`I '의 값은 결코 잠겨 있지 않기 때문에 생각대로 작동하지 않을 수 있습니다. // 반대로, 각 링크가 클릭되면 (루프가 잘 실행됨), 모든 요소의 총 수는 팝업됩니다. // 이것은`I '의 실제 값이기 때문입니다. var elems = document.getElementsByTagName ( 'a'); for (var i = 0; i <elems.length; i ++) {elems [i] .addeventListener ( 'click', function (e) {e.preventDefault (); Alert ( 'I am link #'+ i), false); 값은`lockedinindex`에 잠겨 있습니다. // 루프가 실행되면`I '의 숫자 값은 모든 요소의 합이지만, 함수 표현식이 호출 될 때마다 iife의'lockedInindex '값은`i'에 의해 값이 전달되는 값이므로 링크가 클릭되면 올바른 값이 나타납니다. var elems = document.getElementsByTagName ( 'a'); for (var i = 0; i <elems.length; i ++) {(function (lockedInindex) {elems [i] .addeventListener ( 'click', function (e) {e.preventDefault (); alert ( 'i am link #', wappe); }) (i);} // 다음과 같은 iife를 사용할 수도 있고, 괄호를 사용하여 클릭 프로세싱 기능을 포함시키고 전체 'addeventListener'를 포함하지 않도록 할 수도 있습니다. // 어떤 방식 으로든, 두 예제는 iife와 함께 잠겨있을 수 있지만, 이전 예제는 더 읽기 쉬운 var elems = document.getElementsByTagName ( 'a'); for (var i = 0; i <elems.length; i ++)임을 알았습니다. [i] .addeventListener ( 'click', (letuckeddex) {e) {e) {e) {e); Alert ( 'I Am #' + lockedInindex); }이 마지막 두 가지 예에서 LockedInindex는 문제없이 I에 액세스 할 수 있지만 기능의 매개 변수로 다른 이름의 식별자를 사용하면 개념을 쉽게 해석 할 수 있습니다.
함수를 즉시 실행하는 데있어 가장 중요한 장점 중 하나는 이름이 명명되거나 익명이 아닌 경우에도 기능 표현식을 식별자를 사용하지 않고 즉시 호출 할 수 있으며 현재 변수의 오염없이 클로저를 사용할 수 있다는 것입니다.
자체 실행 익명 기능 ( "자체 실행 익명 기능")의 문제는 무엇입니까?
당신은 그것이 여러 번 언급 된 것을 보았지만, 여전히 명확하게 설명되지는 않았으며, 약어를 좋아한다면 용어를 "즉시 투자 한 기능 표현"또는 iife로 변경하는 것이 좋습니다.
즉시 관련된 기능 표현은 무엇입니까? 즉시 함수 표현식을 호출합니다. 그것은 당신이 호출하게하는 함수 표현과 같습니다.
JavaScript 커뮤니티의 구성원은 개념을 이해하는 것이 더 쉽다고 생각하기 때문에 기사 나 진술에 즉시 투쟁하는 기능 표현 및 IIE를 받아 들일 수 있어야한다고 생각합니다. "자체 실행 익명 기능"이라는 용어는 실제로 정확하지 않다고 생각합니다.
// 다음은 자체 실행 함수이며, 자체 함수를 재귀 적으로 호출합니다. foo () {foo ();}; // 이것은 자체적으로 실행되는 익명 함수입니다. 식별자가 없기 때문에`arguments.callee` 속성을 사용하여 var foo = function () {arguments.callee ();}; // 이것은 익명의 기능으로 간주 될 수 있지만 var foo = fool ()}; // function (); // fupering을 호출하는 것이 'foo'로 대체하는 것이 가능합니다. 익명의 기능은 자체적으로 자체적으로 불러 오지 않더라도 자체적으로 호출하지 않더라도 이와 같은 기능. 그런 다음 즉시 전화했습니다. (function () {/*code*/} ()); // 함수 표현식에 식별자를 추가하는 것은 (즉, 명명 된 함수를 생성) 디버깅에 큰 도움이됩니다. 일단 지명되면이 기능은 더 이상 익명이 아닙니다. (함수 foo () {/ * code */} ()); // iifes는 자체적으로 실행될 수 있지만, 아마도 가장 유용한 패턴은 아니지만 (function () {arguments.callee ();} ()) (function foo () {foo ();} ();} ();} (); 굉장합니다, huh? (function foo () {foo ();} ());위의 예가 기능이 실행되었지만 자체 기능을 실행하지 않기 때문에 자체 이행이라는 용어에 대한 명확한 이해를 제공하기를 바랍니다. 마찬가지로, 즉시 호출 된 함수 표현식은 명명 된 함수 또는 익명 함수 일 수 있기 때문에 익명 함수를 지적 할 필요가 없습니다.
마지막 : 모듈 모드
함수 표현식을 호출 할 때 모듈 패턴에 대해 한 번 이상 상기시켜 주면 무시할 것입니다. JavaScript에 모듈 패턴이없는 경우 아래 예제와 매우 유사하지만 반환 값은 함수 대신 객체를 사용합니다.
var counter = (function () {var i = 0; return {get : function () {return i;}, set : function (val) {i = val;}, 증착 : function () {return ++ i;}}} (); counter.get (); // 0 counter.set (3); counter.increment (); // 4 counter.increment (); // 5 conuter.i; // 정의되지 않은 (`I '는 반환 된 객체의 속성이 아니다) i; // 참조 우리 : 나는 정의되지 않았다 (폐쇄 내부에만 존재 함).모듈 모드 방법은 매우 강력 할뿐만 아니라 간단합니다. 코드가 거의 없으면 메소드 및 속성과 관련된 이름 지정을 효과적으로 활용할 수 있습니다. 객체에서 모든 모듈 코드를 구성하면 글로벌 변수의 오염이 최소화되고 변수를 사용합니다.