한 마디로 이름이 없는 함수, 람다식(Lambda Expression) 이라고도 부른다.
코드를 보면 그냥 한 번에 감이 온다.
// 일반적인 방식
function NamedFunc(){
console.log("일반 함수 실행");
}
// 익명 함수
const anony = function(){
console.log("익명 함수 실행");
}
NamedFunc();
anony();
이것과 비슷한 개념으로 화살표 함수 및 즉시 실행 함수 가 존재한다.
확실히 첫 인상은 비슷한 개념이지만 화살표 함수 같은 경우에는 무시못한 차이점이 존재한다.
익명 함수와 화살표 함수 내부에서 this 키워드의 대상이 완전히 다르다는 것인데 ( 정확하게는 this. 바인딩을 하지 않는다. ), 해당 부분에 대해서 자세히 다루지는 않겠다.
하여간 그냥 단순히 "아, 함수 이름 짓기 귀찮을 때 사용하면 좋겠네~" 라고만 이해하고 넘어가면 절대 안 된다.
익명 함수와 기명 함수(선언 함수, 일반 함수라고도 부른다.)의 가장 큰 차이점은 선언되는 시점이 완전히 다르다는 점이다.
결론부터 말하자면, 어떤 선언 함수보다도 익명 함수가 무조건 늦게 실행된다.
다음 코드를 보자.
console.log("첫번째 실행---------------");
func();
var func = function(){
console.log("익명 함수 실행");
}
function func () {
console.log("선언식 함수 실행");
}
console.log("두번째 실행---------------");
func();
위 코드의 실행 결과는 무엇일까?
"선언식 함수 실행"이 두 번 찍힐까?
아니면 그냥 단순히 에러?
첫 번째 실행에는 선언식 함수, 두 번째 실행에는 익명 함수가 실행되었다.
이유가 무엇일까?
Javascript가 컴파일 과정이 아니라 인터프리터 방식으로 실행되기 때문에?
그 개념으로만 접근하면 두가지 실행 결과 모두 설명이 불가능하다.
첫번째 실행 당시의 코드에서는 func()라는 함수 자체가 선언이 되어있지 않다.
선언식 함수(= 기명함수)는 브라우저 런타임 이전에 선언이 완료되어 있기 때문에?
확실히 맞는 말이다. 기명 함수와 익명 함수의 대표적인 차이를 한 마디로 정리하면,
익명함수 같은 경우는 브라우저가 런타임(RunTime)에 동적으로 선언되는 함수
기명함수 같은 경우는 브라우저가 런타임(RunTime) 이전에 선언되는 함수
여기서 익명 함수에 대해서 다시 설명하기 전에, 먼저 기명 함수 설명을 자세히 보자.
기명함수 같은 경우는 브라우저가 런타임(RunTime) 이전에 선언되는 함수
즉, "첫번째 실행" 콘솔 이후의 func() 코드가 실행되기 전에, 이미 선언적 함수(=기명 함수)인 func가 선언되어있다는 의미이다.
결론부터 말하자면, 이러한 현상을 호이스팅(Hoisting = 끌어올리기) 이라고 한다.
사실 js를 처음 배울 때, var와 let의 차이점을 공부하면서 이미 알고 있었던 개념이다.
하지만 당시에는 그냥 단순히 var 키워드의 불합리성을 보여주는 대표적 현상 정도로만 이해했고, 어차피 그냥 let만 쓰면 되겠지하고 단순하게 넘어갔었다.
함수의 선언에 대해서도 호이스팅 현상이 동일하게 일어난다는 것을 알게 된 뒤에야 MDN 문서를 찾아보았다.
매우 명확하게 호이스팅에 대한 설명이 되어있어서, 쉽게 이해했지만 문제는 또 다른 문장이었다.
"예를 들어, 호이스팅을 변수 및 함수 선언이 물리적으로 작성한 코드의 상단으로 옮겨지는 것으로 가르치지만, 실제로는 그렇지 않습니다. 변수 및 함수 선언은 컴파일 단계에서 메모리에 저장되지만, 코드에서 입력한 위치와 정확히 일치한 곳에 있습니다."
일단 코드 자체가 실제로 옮겨지지 않는다는 것도 새로 알게 된 것이지만,
그것보다도 컴파일 단계라는 부분에서 혼란이 왔었다.
일반적으로 인터프리터 언어와 컴파일 언어 개념에 대해서 비교할 때,
컴파일러 언어는 실행 이전에 컴파일러의 깐깐한 심사 과정을 통과해야 한다.
반면에 인터프리터 언어는 한 번에 한 줄씩 바로바로 실행해서 비교적 더 자유로운 편이다.
그리고 인터프리터 언어의 대표적인 것 중 하나가 바로 Javascript 언어이다.
그런데 위의 MDN 문서에 적힌 문장대로라면,
대표적인 인터프리터 언어인 Javascript 에서 컴파일 단계가 존재한다는 말이 된다.
이게 대체 무슨 소린가 싶었다.
그래서 열심히 구글링을 해보니, 이러한 설명을 찾았다.
결론적으로, Javascript 역시 컴파일 과정을 거친다.
더 정확하게는 현대 JS에서 사용하는 대표적인 엔진이 크롬 V8인데, 여기서 필요에 따라 그 때 그 때 내부에서 컴파일 과정을 거친다. ( 이러한 컴파일러를 JIT(Just-In-Time) 컴파일러라 부른다. ) 그리고 그 이후에 컴파일 되어있는 소스를 인터프리터 방식으로 실행한다.
즉, 크롬 V8 엔진을 사용하는 현대 Javascript는 필요에 따라서 컴파일과 인터프리터 방식이 혼합되어서 사용된다는 것이다.
자바스크립트 엔진은 전통적인 인터프리터일 수도 있고, 특정한 방식으로 바이트코드로 JIT 컴파일을 할 수 있다. - Wiki
대중적인 오해와 달리, Javascript는 인터프리트 형태 자바가 아니다. 간단히 말하면, Javascript는 프로토 타입 기반 객체 생성을 지원하는 동적 스크립트 언어이다. - MDN
아직 조금 더 정리해서 명확하게 해야하는 것은 맞지만,
확실한 것은 Javascript가 단순히 인터프리터 방식으로만 실행되는 것이 아니다는 것이다.
하여간 호이스팅이라는 개념을 통해서, 첫 번째 실행 부분에서 선언적 함수(=기명 함수) 실행이라는 콘솔이 찍히는 것은 이해할 수 있다.
하지만 두 번째 실행 부분은 어떤가?
같은 함수라면 당연히 기명 함수보다 익명 함수가 더 먼저 선언되었고,
그렇다면 더 나중에(더 밑에서) 선언된 "선언적 함수 실행" 콘솔이 찍혀야 정상아닌가?
아니다. 위에서 말한 익명 함수를 다시 보자.
익명함수 같은 경우는 브라우저가 런타임(RunTime)에 동적으로 선언되는 함수
기명 함수는 런타임 이전에 이미 선언되어 있지만, 익명 함수는 런타임이 된 시점에서야 동적으로 선언된다.
즉, 더 위에서 적힌 코드라도 비교적 더 늦게 선언된다는 뜻인데,
사실 이러한 익명 함수의 특성때문에 쉐도잉(Shadowing)을 목적으로 쓰이기도 한다.
정리하자면, 익명 함수는 그 어떠한 기명 함수보다도 늦게 선언된다는 것이다.
댓글 영역