모던 JavaScript 튜토리얼을 읽고 정리하였습니다.
함수 표현식
자바스크립트는 함수를 특별한 종류의 값으로 취급한다. 이전 챕터에서는 함수 선언(Function Declaration)
방식으로 함수를 만들었지만 함수 표현식(Function Expression)
을 사용해서 함수를 만들 수도 있다.
함수표현식으로 함수를 생성해보자.
let sayHi = fuction() {
alert("Hello");
};
함수를 생성하고 변수에 값을 할당하는 것처럼 함수가 변수 sayHi
에 저장된 값이 되었다. 함수가 어떤 방식으로 만들어졌는지에 관계없이 함수는 값이므로 변수에 할당 가능하다.
함수는 값이기 때문에 alert를 이용하여 함수 코드
를 출력할 수도 있다. 아래 예시에서 마지막 줄에 sayHi 옆에 괄호가 없으므로 함수가 실행되는 것이 아니라, 함수의 소스 코드가 문자형으로 바뀌어 반환된다.
function sayHi() {
alert(Hello);
}
alert(sayHi);
변수의 값을 복사해 다른 변수에 할당하는 것처럼 함수를 복사해 다른 변수에 할당할 수도 있다.
function sayHi() {
alert("Hello");
}
let func = sayHi;
func(); // 복사한 함수를 실행
sayHi();
위 예시의 동작 원리는 다음과 같다.
- 함수 선언 방식을 통해 함수를 생성하고, sayHi라는 변수에 저장된다.
- sayHi를 새로운 변수 func에 복사한다. sayHi 다음에 괄호가 없으므로 함수의 반환값이 아니라 함수 그 자체가 복사된다.
- 이젠 sayHi()와 func()로 함수를 호출이 가능하다.
끝에 세미콜론이 있는 이유
함수 선언문과 달리 함수 표현식의 끝에 세미콜론이 붙은 이유는 let sayHi = …;과 같은 구문에서 함수표현식이 코드 블록이 아니라 값처럼 취급되기 때문이다. 따라서 세미콜론은 함수표현식 때문에 붙여진 게 아니라, 구문의 끝이라서 붙여진 것이다.
콜백 함수
함수 표현식에 대한 예시를 좀 더 살펴보자. 매개변수 3개를 갖는 함수, ask(questionm, yes, no)
를 작성해보자. 각 매개변수에 대한 설명은 아래와 같다.
question
질문yes
“Yes”라고 답한 경우 실행되는 함수no
“No”라고 답한 경우 실행되는 함수
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
function showOk() {
alert("동의하셨습니다.");
}
function showCancel() {
alert("취소 버튼을 누르셨습니다.");
}
ask("동의하십니까?", showOk, showCancel);
이렇게 함수를 작성하는 방법은 실무에서 아주 유용하게 쓰인다.
함수 ask의 인수, showOk
와 showCancel
을 콜백 함수
또는 콜백
이라고 불린다. 콜백 함수
란 함수를 함수의 인수로 전달하고, 필요할 때 인수로 전달한 함수를 나중에 호출(called back)하는 것을 말한다. 위 예시에서는 사용자가 yes라고 대답한 경우 showOk가 콜백이 되고, no라고 대답한 경우 showCancel이 콜백이 된다.
아래와 같이 함수 표현식
을 사용하면 코드 길이가 짧아진다. 다음과 같이 이름 없이 선언한 삼수는 익명 함수(anonymous function)
라고 부른다. 익명 함수는 변수에 할당한게 아니므로, ask 바깥에선 접근할 수 없다.
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
ask("동의하십니까?",
function() {alert("동의하셨습니다.");},
function() {alert("취소 버튼을 누르셨습니다.");}
);
함수는 동작을 나타내는 값
문자열이나 숫자 등의 일반적인 값들은 데이터를 나타낸다. 함수는 하나의 동작을 나타낸다. 동작을 대변하는 값인 함수를 변수 간 전달하는 것이다.
함수 표현식 vs 함수 선언문
함수 표현식과 선언문의 차이는 다음과 같다.
문법
- 함수 선언문 : 함수는 주요 코드 흐름 중간에 독자적인 구문 형태로 존재한다.
function sum(a, b) {
return a + b;
}
- 함수 표현식: 함수는 표현식이나 구문 구성(syntax construct) 내부에 생성된다.
let sum = function(a, b) {
return a + b;
}
함수 생성 시점
- 함수 표현식 : 실제 실행 흐름이 해당 함수에 도달했을 때 함수가 생성된다. 따라서 함수가 정의된 코드 밑 줄부터 함수를 호출할 수 있다.
sayHi("John"); // error!
let sayHi = function(name) {
alert('Hello, ${name}');
};
- 함수 선언문 : 함수 선언문이 정의되기 전에도 호출할 수 있다. 이게 가능한 이유는 자바스크립트 내부 알고리즘 때문이다. 자바스크립트는 스크립트를 실행하기 전, 준비 단계에서 전역에 선언된 함수 선언문을 찾고 해당 함수를 생성한다. 스크립트가 진짜 실행되기 전 초기화 단계에서 함수 선언 방식으로 정의한 함수가 생성되는 것이다.
sayHi("John");
function sayHi(name) {
alert('Hello, ${name}');
};
스코프
- 함수 선언문 : 코드 블록 내에 위치하면 해당 함수는 블록 내 어디서든 접근할 수 있다. 하지만 블록 밖에서는 함수에 접근하지 못한다.
let age = prompt("나이를 알려주세요.", 18);
if (age < 18) {
function welcome() {
alert("안녕!");
}
} else {
function welcome() {
alert("안녕하세요!");
}
}
welcome(); // Error: welcome is not defined
- 함수 표현식 : if 문 밖에서 welcome 함수를 호출하고자 한다면 If 문 밖에서 선언한 변수 welcome에 함수 표현식으로 만든 함수를 할당하면 된다.
let age = prompt("나이를 알려주세요", 18);
let welcome;
if (age < 18) {
welcome = function() {
alert("안녕!");
};
} else {
welcome = function() {
alert("안녕하세요!");
};
}
welcome(); // 제대로 동작한다.
물음표 연산자 ?를 사용하면 위 코드를 좀 더 단순화할 수 있다.
let age = prompt("나이를 알려주세요.", 18);
let welcome = (age < 18) ?
function() { alert("안녕!"); };
function() { alert("안녕하세요!"); };
welcome();
함수 선언문 vs 함수 표현식
함수 선언문을 이용해 함수를 선언하는 걸 먼저 고려하는 게 좋다. 함수 선언문으로 함수를 정의하면, 함수가 선언되기 전에 호출할 수 있어서 코드 구성을 좀 더 자유롭게 할 수 있다.
삼수 선언문을 사용하면 가독성도 좋다. let f = function(…) {…}보다 function f(…) […]을 찾는게 더 쉽다.
Comments