함수 선언문과 함수 표현식, 함수 호이스팅과 변수 호이스팅의 차이를 확실하게 알아보자.
함수는 입력된 값을 가공해서 결과물을 반환하는 코드 블럭이다.
let price = 0 // 물품 금액
let paidAmount = 0 // 지불한 금액
let change = 0 // 거스름돈
price = 4800
paidAmount = 10000
change = paidAmount - price // 5200
price = 5500
paidAmount = 6000
change = paidAmount - price // 500
price = 400
paidAmount = 1000
change = price - paidAmount // -600?? 실수로 반대로 빼서 완전히 잘못된 결과 반환
// 위의 반복되는 코드를 하나의 함수로 만들면서 실수 방지 가능
const changeCalculator = function(paidAmount, price) {
return paidAmount - price;
};
let change = 0;
// 반복되는 동작을 하나의 함수로 만들어서 재사용
change = changeCalculator(10000, 4800); // 5200
change = changeCalculator(6000, 5500); // 500
change = changeCalculator(1000, 400); // 600
// 오늘 하루만 구매한 가격에 50% 할인 이벤트!!!!
const changeCalculator = function (paidAmount, price) {
return paidAmount - (price * 0.5);
}; // 함수에서만 수정해주면서 아래 코드는 건드리지 않아도 됨.
let change = 0;
change = changeCalculator(10000, 4800); // 7600
change = changeCalculator(6000, 5500); // 3250
change = changeCalculator(1000, 400); // 800
const changeCalculator = function (..., ...) {
...
...
}; // 아~ 거스름돈을 계산해주는 함수구나.
자바스크립트에서 함수를 사용하려면 위의 그림처럼 두 가지 절차가 필요하다.
함수 정의를 먼저 자세히 알아보자.
함수를 사용하려면, 사용할 함수에 대해 미리 정의를 해야한다. 함수를 정의하는 방법에는 4가지가 있다.
function add(x, y) {
return x + y;
}
const add = function (x, y) {
return x + y;
};
const add = new Function('x', 'y', 'return x + y');
const add = (x, y) => x + y;
4가지 전부 함수를 정의하는 방법이지만 각 방법마다 조금씩 차이가 있다.
그 중에서 함수 선언문과 함수 표현식의 차이를 알아보자.
자바스크립트의 함수는 객체이다. 객체를 객체 리터럴로 생성이 가능한 것 처럼, 함수도 함수 리터럴로 생성이 가능하다. 함수 리터럴은 function 함수이름(매개변수) {함수 몸체}
로 표현된다.
함수 선언문, 함수 표현식 둘 다 함수 리터럴과 형태가 동일하다. 그러면 어떻게 함수 선언문과 함수 표현식을 구분하는지 한 번 알아보자.
// 함수 선언문
function add(x, y) {
return x + y;
}
// 함수 표현식
const add = function add(x, y) {
return x + y;
}
두 개 모두 함수 리터럴(function add(x, y) {...}
)로 만들어졌지만 자바스크립트가 문맥을 보고 선언문인지 표현식인지 판단하게 된다.
const add1 = function sum(x, y) {
return x + y;
};
//함수이름을 생략한 함수 표현식
const add2 = function (x, y) {
return x + y;
};
console.log(add1(1, 2)); // 3
console.log(sum(1, 2)); // ReferenceError: sum is not defined
console.log(add2(1, 2)); // 3
function
키워드로 시작하고 함수이름을 생략할 수 없다. 자바스크립트는 함수 선언문으로 해석하게 되면 함수이름으로 식별자를 암묵적으로 생성한다. 그렇기 때문에 함수를 선언하고 함수 외부에서도 호출할 수 있다. // 함수 선언문
function add(x, y) {
return x + y;
}
// 자바스크립트가 암묵적으로 식별자를 생성했기 때문에 함수 외부에서 호출가능
console.log(add(1, 2)); // 3
다시 한 번 말하지만, 함수 호출은 함수이름으로 하는 게 아닌 함수 객체를 가리키는 식별자로 호출한다.
console.log(add1(1, 2)); // 3
console.log(add2(1, 2)); // TypeError: add2 is not a function
function add1(x, y) {
return x + y;
}
var add2 = function (x, y) {
return x + y;
};
위의 코드를 실행해보면, 함수 선언문으로 정의한 함수는 함수 선언 전에 호출이 가능한 반면, 함수 표현식으로 정의한 함수는 함수 선언 전에 호출이 불가능하다.
이러한 차이가 나는 이유는 함수 생성 시점이 다르기 때문이다.
함수 생성 시점의 차이를 알아보기 전에 호이스팅에 대해 먼저 알아보자.
console.log(add1(1, 2)); // 3
console.log(str); // undefined
// 함수 선언문
function add1(x, y) {
return x + y;
}
// 변수 선언문
var str = '호호'
함수 선언문과 변수 선언문을 정의하기 전에 식별자가 불려와지는 걸 볼 수 있다. 그 이유는 런타임 이전에 호이스팅이 발생했기 때문인데,
undefined
로 초기화가 된다.결국 두 선언문은 런타임 이전에 식별자가 초기화되어 있어서, 선언문으로 함수와 변수가 정의되기 전에 식별자를 불러오는 게 가능하다.
이렇게 선언문이 코드의 선두로 끌어 올려진 것 처럼 동작하는 자바스크립트 고유의 특징을 호이스팅이라고 한다.
다시 함수 생성 시점의 차이가 나는 이유로 돌아오면,
console.log(add1(1, 2)); // 3
console.log(add2(1, 2)); // TypeError: add2 is not a function
function add1(x, y) {
return x + y;
}
var add2 = function (x, y) {
return x + y;
};
함수 선언문은 런타임 이전에 이미 함수 객체로 초기화가 되어 함수 정의 전에 호출할 수 있는 반면, 함수 표현식은 런타임 이전에 undefined
로 초기화가 되었기 때문에 add2 is not a function
이라는 에러가 발생하게 된다. 결국 함수 표현식은 런타임 도중 var add2 = function ...
위치에 왔을 때 함수가 정의되기 때문에 함수 선언문과 함수 생성 시점의 차이가 나는 것이다.