logo태영이의 공부방

[JavaScript] 값 vs. 식 vs. 문

2022년 07월 17일

값 Value

value이란 식(표현식)이 평가evaluate되어 생성된 결과를 말한다.

평가란 식을 해석해서 값을 생성하거나 참조하는 것을 의미한다.

변수에 할당되는 것은 값이므로 a라는 변수에 1 + 2를 할당한다면 a에 3이 할당된다.

이 말은 곧 아래 코드와 같다.

var a = 1 + 2 // a = 3
// a 변수에 1 + 2가 평가되어 생성된 3이 할당

위와 같은 방법으로 값을 식으로 생성할 수도 있지만 리터럴을 사용하는 가장 기본적인 방법도 존재한다.

리터럴 Literal

리터럴literal이란 사람이 이해할 수 있는 문자 또는 약속된 기호(' ', " ", ., [ ], , / 등)를 사용해 값을 생성하는 표기법을 말한다.

리터럴은 자바스크립트 엔진에 의해 런타임에 평가되어 값을 생성한다. 즉, 값을 생성하기 위해 미리 약속한 표기법이다.

리터럴을 사용해 아래와 같이 다양한 종류의 값을 생성할 수 있다.

10 // 정수 리터럴
10.2 // 부동소수점 리터럴
0b00000001 // 2진수 리터럴
0o001 // 8진수 리터럴
0x41 // 16진수 리터럴
'hello' // 문자열 리터럴
true // 불리언 리터럴
null // null 리터럴
undefined // undefined 리터럴
{ username: 'Mike', phone: '010-0000-0000' } // 객체 리터럴
[ 'apple', 'orange', 3] // 배열 리터럴
function() {} // 함수 리터럴
/[^a]/g // 정규 표현식 리터럴

표현식 Expression

표현식(식)expression은 값으로 평가될 수 있는 모든 문(statement)을 의미한다.

이 말은 곧, 표현식이 평가되면 새로운 값을 생성하거나 기존의 값을 참조한다는 것이다.

위에서 리터럴은 값을 생성(평가)한다 했으므로, 리터럴은 그 자체로 표현식이다.

표현식은 리터럴, 식별자, 연산자, 함수 호출 등의 조합으로 이뤄질 수 있다.

10 // 리터럴 표현식
 
var a = 1 + 2 // 식별자 표현식, x > 3으로 평가 됨
 
x = 3 // 연산자 표현식
 
add() // 함수/메서드 호출 표현식

이때 표현식과 표현식이 평가된 값은 동등한 관계이므로 표현식은 값처럼 사용할 수 있다. 다시 말해, 값이 위치할 수 있는 자리에는 표현식도 위치할 수 있다.

let x = 10 + 20; // x는 30으로 평가된다.
x * 2; // 30 * 2
// 표현식은 다른 표현식의 일부가 되어 새로운 값을 만들어낼 수 있다.

추가로 표현식은 반드시 상태를 바꿀 필요는 없다. 아래 예제로 알아보자.

const x = 5; // x는 상태(state)이다.
 
x + 3 // 표현식
x - 2 // 표현식
 
console.log(x) // 2, 값이 변화되지 않는다.

여러 표현식에도 불구하고 값이 변하지 않은 x처럼 표현식은 반드시 상태를 바꿀 필요는 없다는 것이다.

정리해보자면 표현식은 아래와 같은 특징을 갖는다.

  • 표현식은 값을 만들어낸다.
  • 표현식은 값처럼 사용할 수 있다.
  • 표현식은 반드시 상태를 바꿀 필요는 없다.

Immediately Invoked Function Expression, IIFEs

IIFEs는 즉시 호출되는 함수 표현식을 말한다.

위에서 익명 함수는 표현식으로 쓰일 수 있다고 했다. 자바스크립트에서 값이 들어갈 수 있는 곳에 괄호를 쓸 수 있다면, 익명 함수를 값으로 넘길 수 있다는 것이다.

익명 함수를 괄호 속에 넣는다면 즉시 같은 익명 함수를 반환한다.

function () {} // 유효하지 않은 코드지만, 괄호를 추가한다면
(function () {}) // function () {}를 리턴한다.
 
// 익명함수 즉시 호출
(function () {
  return 5;
})() // 5
 
// 인자를 넘길 수도 있다.
(function (x) {
  return x;
})(10); // 10

문 Statement

statement은 프로그램을 구성하는 기본 단위이자 최소 실행 단위이다. 문의 집합으로 이루어진 것이 바로 프로그램이며, 문을 작성하고 순서에 맞게 나열하는 것이 프로그래밍이다.

여러 토큰으로 구성되며, 여기서 토큰이란 문법적인 의미를 가지며 문법적으로 더 이상 나눌 수 없는 코드의 기본 요소를 의미한다.

예를 들어 키워드, 식별자, 연산자, 리터럴, 세미콜론(;), 마침표(.) 등이 있겠다.

문은 명령문이라고도 부른다. 이 말은 즉, 문이 실행되면 명령이 실행되고 무슨 일인가가 일어나게 된다는 것이다.

문은 선언문, 할당문, 조건문, 반복문 등으로 구분 가능하다.

자바스크립트의 문

  • if
  • if-else
  • while
  • do-while
  • for
  • switch
  • for-in
  • with (deprecated)
  • debugger
  • variable declaration

표현식인 문 vs. 표현식이 아닌 문

표현식은 문의 일부일 수도 있고 그 자체로 문이 될 수도 있다.

// 변수 선언문은 값으로 평가 불가 > 표현식 X
var x
// 1, 2, 1 + 2, x = 1 + 2 모두 표현식
// 아래 구문은 표현식이면서 완전한 문이기도 하다.
x = 1 + 2

표현식인 문과 표현식이 아닌 문을 구별하는 가장 간단한 방법은 변수에 할당해 보는 것이다.

var a = function () {} // 할당 가능 > 함수 선언문은 표현식 O
var b = var a // 할당 불가 > 변수 선언문은 표현식 X
var c = if (x > 1) { console.log(x); } // 할당 불가 > 조건문은 표현식 X
var d = for (;;) {} // 할당 불가 > 반복문은 표현식 X

표현식인 문은 값처럼 사용할 수 있다.

// 표현식인 문은 값처럼 사용할 수 있다
x = 100 // 평가(evaluate)할 경우 100이 된다.
var foo = (x = 100)
console.log(foo) // 100

함수 선언, 함수 표현식, 네임드 함수 표현식

// 함수 선언, 문장이다.
function foo(x) {
  return x.value;
}
 
// 함수 표현식, 표현식이다. (ex. 익명함수)
console.log(foo(function () {}));
 
// 네임드 함수 표현식, 표현식이다. (이름이 붙은 익명 함수)
console.log(foo(function fooName() {})); 

선언으로서의 함수 vs. 표현식으로서의 함수

값이 들어올 곳에 함수를 선언하면 자바스크립트는 함수를 값으로 다루려 할 것이다. 만약 함수가 값으로 사용될 수 없다면 에러가 발생한다.

반면 값이 들어가는 곳이 아닌 위치(ex. 블록 문장, 모듈, 스크립트)의 전역 단계Global level에 함수를 선언하는 것은 함수 선언이다.

if () {
  function foo() {} // 블록의 가장 상위 레벨, 함수 선언이다.
}
 
function foo() {
  return function hello() {
    function bye() {} // 블록의 가장 상위 레벨, 함수 선언이다.
  }
}
 
function foo() {} // 전역 레벨, 함수 선언이다.
 
function foo() {
  return function hello() {} // 네임드 함수 표현식
}
 
foo(function () {}) // 익명 함수 표현식
 
function () {} // Error: 함수 문장은 이름이 필요합니다.

세미콜론 vs. 콤마 연산자

표현식 뒤에 세미콜론(;)만 추가한다면 표현식을 표현식인 문으로 바꿀 수 있다.

10 + 20 // 표현식
foo(10 + 20) // 값이 들어가야 할 곳에서 사용 가능하다.
 
10 + 20; // 표현식 문
foo(10 + 20;) // Syntax Error

추가로 세미콜론은 여러 줄의 문장을 하나의 줄에 넣을 수 있게 해준다.

콤마 연산자는 여러 개의 표현식을 연결할 수 있게 해준다. 이 때, 마지막 표현식만 반환한다.

let x = 1; function foo() {}; let y; // 여러 줄의 문장을 하나의 줄로
 
console.log( (1, 2, 3 + 4) ) // 7, 마지막 표현식 반환
 
function foo() { return 1, 2, 3 + 4 }
foo() // 7, 모든 표현식은 왼쪽에서 오른쪽으로 계산되고, 마지막 것이 반환된다.

객체 리터럴 vs. 블록 문장

자바스크립트에는 루프를 중단할 때 유용한 label이란 것이 있다.

loop: {
  for (const i=0; i<4; i++) {
    for (const j=0; j<5; j++) {
      break loop; // 바깥 loop 중단, 전체 루프를 중단한다.
    }
  }
}

라벨을 어떠한 표현식이나 표현식인 문에 붙일 수 있지만, 변수를 만드는 것은 아니다.

이때 쓰이는 중괄호({})는 문장과 표현식인 문들을 그룹화하는데 도움을 준다.

그렇다면 객체 리터럴과 블록 문장은 어떻게 구분하는 것일까. 아래 예제로 알아보자.

// 블록 문장
console.log( {var x = 1; foo(); 1 + 2} ) // 3
console.log(x) // 1
 
// 객체 리터럴과의 비교
console.log( {apple: 5, banana: 2} ); // 객체 리터럴
console.log( {var x = 1, foo(), 1+2} ) // SyntaxError 블록 문장

위와 같이 console.log()는 객체 리터럴은 인자로 받을 수 있지만, 블록 문장은 받을 수 없다. 이는 블록 문장을 값이나 표현식으로 사용할 수 없기 때문이다.

{} + 1 // 1
{2} - 1 // -1
{1+2} + 1 // 1

문장은 아무것도 반환하지 않기 때문에 위 예제의 블록 문장에서 반환된 값은 0으로 강제 형변환되어 피연산자로 사용된다.

ASI Automatic Semicolon Insertion

ASIAutomatic Semicolon Insertion는 세미콜론 자동 삽입 기능을 말한다.

코드 블록은 언제나 문의 종료를 의미하는 자체 종결성을 갖기 때문에 중괄호로 묶은 코드 블록 뒤에는 세미콜론을 붙이지 않는다.

문의 끝에 붙이는 세미콜론은 생략 가능한데, 자바스크립트 엔진이 소스코드를 해석할 때 문의 끝이라고 예측되는 지점에 자동으로 세미콜론을 붙여주는 세미콜론 자동 삽입 기능이 암묵적으로 수행되기 때문이다.

ASI의 동작 결과와 개발자의 예측이 일치하지 않는 경우가 가끔 있기도 해 세미콜론 사용을 권장하는 분위기라고 한다.

정확히 말하자면 개발자가 ASI의 동작을 제대로 예측하지 못해 아래와 같이 제대로 활용하지 못하는 경우가 있는 것이다.

function foo() {
  return
  {
  }
  // ASI의 동작 결과 => return; {};
  // 개발자의 예측 => return {};
}
 
console.log(foo()) // undefined
 
var bar = (function () {})(function () {})()
// ASI의 동작 결과 => var bar = function () {}(function() {})();
// 개발자의 예측 => var bar = function () {}; (function() {})();
// TypeError: (intermediate value)(...) is not a function

정리

  • 값: 식(표현식)이 평가되어 생성된 결과
  • 평가: 식을 해석해서 값을 생성하거나 참조하는 것
  • 리터럴: 값을 생성하기 위해 미리 약속한 표기법
  • 표현식: 값으로 평가될 수 있는 문
    • 리터럴, 식별자, 연산자, 함수 호출 등의 조합
    • 값처럼 사용 가능
  • 문: 프로그램을 구성하는 기본 단위이자 최소 실행 단위
    • 선언문, 할당문, 조건문, 반복문 등으로 구분
    • 여러 토큰으로 구성
  • 토큰: 문법적으로 더 이상 나눌 수 없는 코드의 기본 요소
    • ex. 키워드, 식별자, 연산자, 리터럴, 세미콜론(;), 마침표(.) 등
  • 표현식인 문 vs. 표현식이 아닌 문
    • 표현식인 문: 값으로 평가될 수 있는 문
    • 표현식이 아닌 문: 값으로 평가될 수 없는 문
  • 세미콜론 자동 삽입 기능: 암묵적으로 수행되지만 세미콜론 사용을 권장