[펌] +function() 의 원리
출처 : http://blog.coderifleman.com
오픈소스나 레거시 읽다 보면 종종 +function(){}() 같은 코드를 마주하게됩니다. 이 코드가 혼란스러운 분들을 위해 +function(){}()이 무엇인지 그리고 어떻게 동작하는 것인지 간략히 정리해보겠습니다.
엔진이 함수를 실행하는 방법
함수를 실행하기 위해서는 이름(식별자)이 필요합니다. 이름이 있어야 스코프에서 값을 참조할 수 있기 때문입니다.
예를 들어 function foo(){}를 정의하면 foo(); 구문을 이용해 함수를 실행할 수 있습니다.
엔진이 함수 선언문을 만나면 식별자를 관리하는 특별한 집합(EnviromentRecord)에 함수의 이름을 식별자로 넣고 함수 객체를 생성하여 참조합니다. 그리고 함수 실행 구문 중 foo를 만나면 값을 스코프를 통해 가져옵니다. 그 다음 구문이 () 이므로 실행 가능하다면 실행합니다.
만약 스코프에서 식별자를 찾지 못했다면 참조 에러(ReferenceError)를 출력하고, 식별자는 찾았지만 실행할 수 없는 타입이라면 타입 에러(TypeError)를 출력합니다.
not(); // ReferenceError: not is not defined
var foo = 'some';
foo(); // TypeError: foo is not a function
익명함수를 선언하는 방법
function(){} 구문은 이름 없는 “익명함수” 이므로 엔진이 스코프를 통해 값을 가져올 수 있는 방법이 없습니다. 따라서 이 문법을 실행하면 함수의 이름이 필요하다고 문법 오류를 출력합니다.(이 오류 메시지는 브라우저 마다 다릅니다.)
function(){} // SyntaxError: function statement requires a name
이름 없는 함수를 선언할 수 있는 유일한 경우는 함수를 값으로 사용(전달, 대입, 반환, 연산)할 때 입니다.
var func = function(){console.log('ok');}() // ok some(function(){console.log('ok');})() // ok return function(){console.log('ok');}() // ok (function(){console.log('ok');})(); // ok +function(){console.log('ok');}() // ok !function(){console.log('ok');}() // ok
자바스크립트 엔진은 단항연산자(-, +, ~, !)를 만나게 되면 function(){}을 값으로 평가합니다. 쉽게 말해 연산을 위해 함수 객체를 생성하게 되고 최종적으로 () 구문을 이용해 실행할 수 있는 것입니다.
+function(){}은 함수 객체를 + 하려고 했으므로 결과로 NaN이 출력됩니다.
+function(){} // NaN
결론
결국 +function(){}()은 익명 함수를 즉시 실행시키기 위해 엔진의 원리를 이용해 만든 편법입니다.
이 원리를 이용한 즉시 실행 함수 중 가장 대중적인 방식은 (function(){})()입니다. ()는 구문 평가를 하는데 평가된 결과가 함수이니 함수 객체를 만들고 이어서 () 구문으로 즉시 실행하는 방식입니다.
(function(){}) // function() 객체 (function(){})() // 즉시 실행
남이 읽을때 혼란스럽지 않아야 좋은 코드라고 할 수 있겠죠. 따라서 비대중적인 +function(){}() 보다 (function(){})() 사용하여 코드를 읽는 개발자가 즉시 실행하는 함수 임을 쉽게 알 수 있도록 하는편이 좋겠습니다.
자바스크립트는 구문이 유연하기 때문에 자신만의 규칙이나 법칙을 만들기 쉽습니다. 하지만 이는 협업시 독이 될 수 있음을 명심해야합니다.