해당 시리즈는 Leonardomso의 33 Concepts Every JavaScript Developer Should Know 를 보고 공부, 정리한 시리즈이며, 자세한 내용은 링크를 확인하길 바란다.
자바스크립트 코드의 기초적인 개념인 Expression 표현식 과 Statement 문 에 대해서 알아보자.
추가적으로 함수 표현식과 함수 선언식의 차이도 함께 알아보자.
표현식
표현식은 값(value) 로 평가될 수 있는 문(statement) 를 의미한다.
즉, 값을 리턴하는 모든 문이 표현식이다.
아래 코드들은 모두 표현식이다.
1 + 5
10
'JavaScript'
이들은 각각 6
, 5
, 'JavaScript'
라는 값을 리턴한다.
이처럼 리터럴, 식별자, 연산자, 함수 호출 등의 조합으로 이루어져 값으로 평가될 수 있는 문은 모두 표현식이다.
// 리터럴 표현식
10
'Hello'
// 식별자 표현식 (이미 선언되었다고 가정)
x
numbers[0]
fruit.cost
// 연산자 표현식
1 + 2
x = 10
x !== 10
// 함수 호출 (이미 선언되었다고 가정)
sum()
문
위키백과에 나와 있는 Statement 에 대한 정의를 먼저 보자.
문(statement)은 명령형 프로그래밍 언어의 가장 작은 독립 요소이다. 프로그램은 하나 이상의 문이 연결되어 형성된다. 문은 식(expression)과 같은 내부 요소를 포함할 수 있다.
Statement 는 프로그램을 구성하는 가장 작은 독립 요소, 즉 기본 단위이자 최소 실행 단위이다.
Statement 는 명령문이라고도 불리며, 컴퓨터에서 명령과 지시를 내리는 역할을 한다.
선언문, 할당문, 조건문, 반복문 등으로 나눌 수 있다.
// 변수 선언문
var x;
// 할당문
x = 10
// 함수 선언문
function f1 () {}
// 조건문
if (x > 5) {}
// 반복문
for (let i = 0; i < x; i++) {}
표현식과 문은 어떤 차이가 있나?
먼저, 정리하자면 Expression 은 Statement 의 일부이다.
앞서 Expression 을 정의할 때도, 값으로 평가될 수 있는 문(statement) 이라고 했던 것처럼 표현식은 문에 속해있다.
아래 코드를 보자.
var x; // 1
x = 1 + 2; // 2
1번 코드는 변수 선언문으로, Statement 이나 값으로 평가될 수 없음으로 Expression 은 아니다.
2번 코드는 할당문으로, 1 + 2 는 값으로 평가되는 표현식이기에 Expression 이면서 Statement 이다.
즉, 표현식은 그 자체로 문(statement) 일 수도 있고, 문(statement) 의 일부일 수도 있다.
그렇다면 표현식이 아닌 문과 표현식인 문을 어떻게 구분할까?
간단하다.
변수는 즉, 식별자는 메모리 공간에 할당된 값의 메모리 주소를 가리키는 이름이다.
그렇기에 값이 평가되지 않는 문(statement)은 변수에 할당될 수 없다.
표현식은 값으로 평가될 수 있는 문이고, 표현식이 아닌 문은 값으로 평가될 수 없는 문이기에 변수에 할당하여 파악할 수 있다.
앞서 본 코드를 변수에 할당하여 확인해보자.
const a = x = 1 + 2
console.log(a) // 3
const b = var x // Uncaught SyntaxError: Unexpected token 'var'
위 코드의 결과처럼, 표현식인 할당문 x = 1 + 2
는 변수 a
에 할당되는 것을 볼 수 있는 반면,
표현식이 아닌 선언문 var x
는 변수 b
에 할당되지 못하고 에러를 발생하는 것을 볼 수 있다.
이처럼, 값으로 평가되는지 여부에 따라 표현식인 문 와 표현식이 아닌 문(Statement) 로 구분할 수 있다.
표현식과 문(Statement) 을 구분하는 다른 방법 중에 완료 값(Completion Value)을 보고 판단하는 것이다.
완료 값이란 크롬 개발자 도구(콘솔)에서 statement 를 실행하고 나서 출력되는 값이다.
표현식이 아닌 문(Statement) 은 undefined
를 완료 값으로 출력한다.
반면에, 표현식인 문 은 평가된 값을 완료 값으로 출력한다.
위 사진처럼, 표현식이 아닌 변수 선언문 var num = 3
는 undefined
를 출력하고,
표현식인 num
, num + 3
, 할당문 num = 1 + 2
는 각각 평가된 값을 출력하는 것을 볼 수 있다.
추가적으로 함수 declaration 과 expression 의 차이도 알아보자.
자바스크립트에서 함수를 선언할 수 있는 방법은 크게 4가지가 있으며 이 중에서 함수 선언식과 함수 표현식의 차이를 알아보자.
(자바스크립트의 함수에 관한 내용은 따로 정리해서 올릴 예정이기에 여기서는 최대한 간소하게 설명할 것이며, 함수 선언식과 함수 표현식의 차이에 대해서 좀 더 중점적으로 다루겠다.)
함수 선언식은 표현식이 아닌 문(Statement) 이다.
다른 프로그래밍 언어에서의 함수 선언과 비슷한 형식으로 함수를 선언한다.
function 함수명(인자) {
로직
}
함수 표현식은 문자에 담겨 있는 대로 표현식이다.
자바스크립트만의 표현 방법으로, 변수에 함수를 할당하는 형식이다.
var 함수명 = function (인자) {
로직
}
다른 언어들과 다르게 자바스크립트에서 함수는 객체이자 값처럼 변수에 할당되거나 객체 프로퍼티의 값이 될 수 있는 일급 객체이다.
일급 객체이기에 함수를 값처럼 자유롭게 사용할 수 있고, 변수에 할당할 수 있다.
앞서 말한대로 함수 선언식은 표현식이 아닌 문(Statement) 이며, 함수 표현식은 표현식인 문(expression) 이다.
이는 단순히 변수에 할당될 수 있는지 없는지의 차이만을 갖는 것이 아닌 하나 더 큰 차이를 갖는다.
바로 호이스팅의 차이다.
(호이스팅에 대해서 간단하게만 정의하고 가자. 호이스팅은 다른 게시글을 통해 따로 정리해서 올릴 예정이다.)
코드를 해석할 때 선언된 위치에 상관없이 맨 위로 끌어 올려져서 선언되는 것처럼 보이는 자바스크립트 엔진만의 특징
즉, 해당 코드를 실행하지 않아도 이미 선언된 것처럼 보인다는 말이다.
아래 코드를 보면서 확인해보자.
console.log(x) // undefined
var x = 10
console.log(x) // 10
코드를 보면, x
를 선언하기도 전에 console.log() 를 통해 x
를 출력한 결과, 에러가 아닌 undefined
가 출력된다.
이후 x
변수가 할당문이 실행되고 나서 10
이라는 할당된 값을 출력하는 것을 볼 수 있다.
이처럼 변수 선언 및 할당 관련 코드가 실행되기 전에 변수가 미리 선언되어지는 특징이 호이스팅이며, 구분을 위해서 변수 호이스팅이라 하겠다.
변수 호이스팅은 위 코드의 결과처럼, 변수를 미리 선언하고 undefined
로 초기화한다. (이는 var
키워드를 선언한 변수만 해당되며, let
과 const
키워드로 선언한 변수의 호이스팅에 대해서는 호이스팅 관련 게시글을 통해 설명하겠다.)
함수도 변수와 마찬가지로 호이스팅이 가능하다.
const answer1 = add(1, 2)
function add(a, b) {
return a + b
}
console.log(answer1) // 3
위 코드도 add
라는 함수가 정의되기 전에, answer1
이라는 변수에 아무런 에러 없이 할당되며 그 값이 무사히 출력되는 것을 볼 수 있다.
이처럼 함수 선언식을 통해 함수를 정의할 경우 호이스팅이 되며, 구분을 위해 함수 호이스팅이라 하겠다.
이 함수 호이스팅은 변수 호이스팅와 차이점이 있는데, 변수 호이스팅의 경우, 변수를 미리 선언하고 undefined
로 초기화하는 반면에, 함수 호이스팅의 경우, 함수를 미리 선언하고, 함수 객체로 초기화한다.
이러한 호이스팅의 차이가 함수 선언식과 함수 표현식의 차이를 만들어낸다.
함수 선언식은 함수 호이스팅을 따른다.
함수 표현식은 함수 자체를 값으로 사용하여 변수에 할당하였기에 함수 호이스팅이 아닌 변수 호이스팅을 따른다.
그렇기에 함수 선언 전에 함수를 사용하는 과정에서, 함수 선언식을 통해 함수를 정의했다면 함수 호이스팅에 의해 함수 호출이 가능하지만, 함수 표현식을 통해 함수를 정의했다면 변수 호이스팅을 따르기에 함수가 아닌 undefined
가 호출되어 에러를 발생한다.
console.log(plus(3, 2)) // 5
console.log(minus(3, 2)) // TypeError: minus is not a function
// 함수 선언식
function plus(a, b) {
return a + b
}
// 함수 표현식
var minus = function (a, b) {
return a - b
}
위 코드처럼 함수 선언식으로 정의한 plus
함수는 함수 호이스팅으로 함수 객체가 할당되어있어 5
라는 출력값을 정상적으로 얻을 수 있지만,
함수 표현식으로 정의한 minus
변수에는 함수가 아닌 undefined
가 할당되어있기에 minus
가 함수가 아니라는 TypeError 를 발생시킨다.
이처럼 서로 다른 호이스팅에 영향을 받는 차이를 갖는다.
사실 함수 호이스팅으로 인해 많은 혼란을 야기시킬 수도 있는 문제가 존재한다.
그렇기에 둘 중 하나의 방식으로 함수를 선언해야한다면 되도록 함수 표현식을 사용하자!
Airbnb 의 JS 스타일 가이드도 함수 표현식 사용을 권장하며,
JSON 을 창안한 더글라스 크락포 또한 그의 책 'JavaScript: The Good Parts' 에서 함수 표현식 사용을 권장한다.
표현식(expression)은 값으로 평가될 수 있는 문(statement) 이고,
문(Statement)는 프로그램 실행의 기본 단위로 명령문이라고도 불린다.
표현식은 문의 일부이며, 문(statement)는 표현식인 문과 표현식이 아닌 문으로 구분되며, 이 둘의 차이는 변수에 할당해봄으로써 알 수 있다.
함수 선언식(Function Declaration) 은 표현식이 아닌 문이며, 함수 표현식(Function Expression) 은 표현식인 문이다.
이 두 방법 모두 함수를 정의하는 방법이나, 어떤 호이스팅을 따르냐에 따라 차이를 갖는다.
함수 선언식은 함수 호이스팅을 따르며, 함수 표현식은 변수 호이스팅을 따른다.
다만, 함수 호이스팅으로 인해 함수 선언식을 사용하여 함수를 선언하며 혼란을 야기시킬 수 있으니,
되도록 함수 표현식을 쓰자.