값 , 리터럴, 그리고 표현식 (부록: 함수 선언식은 표현식일까)

alang·2021년 9월 4일
0

JS 기본기 다지기

목록 보기
2/4

개요

값 (Value)

프로그래밍 언어에서 값(value)이란 : 평가(evaluate)를 통해서 생성되어지는 결과

평가(Evaluate) : 식을 해석해서 값을 생성하거나 참조하는 것
10 + 20 과 같은 연산자, 함수의호출과 같이 어떠한 return, 즉 값을 반환하는 과정을 모두 평가라고 할수 있다..

10 + 20; // 30이라는 값을 반환하므로 10 + 20은 평가 된다.
(()=>{return 4})() // 4라는 값을 반환한다.

*변수에는 값이 저장된다.

변수는 하나의 값을 저장하기위한 메모리 공간이고, 그 변수의 식별자는 해당 메모리 공간을 가리키는 위치를 담는다.
이를 바꾸어 말하면, 변수에 할당이 가능한것은 뿐이다.

*그렇다면 함수도 값이란건가??

JavaScript에서는 let foo = () => {}와 같은 형태의 함수표현식이라는 것이 존재한다. (표현식이란 것은 아래에 설명) let은 변수선언을 의미하고, 이때의 foo는 해당 변수의 식별자가 된다. 그렇다면 ()=>{}는 해당 변수에 저장되는 값이된다는 것일까?
그렇다.
JavaScript에서의 모든 함수는 일급함수이다. 일급함수란?
일급함수에 대해 간단히 설명하자면, 값으로 다루어지는 함수를 의미한다.
그러므로 JavaScript에서는 함수를 변수에 담을수도, 객체에도 담을 수 있는 등 기존의 일반적인 값들과 동일하게 사용되어질 수 있다.

그렇다면 함수선언식으로 선언된 함수또한 일급함수인걸까? 이부분에 대해서는 표현식(Expression)에 대해서 다룬 후 이야기해보자.

리터럴(Literal)

리터럴(Literal)이란 : 사람이 이해할 수 있는 문자, 또는 약속된 기호를 사용해 값을 생성하는 표기법
프로그래밍 언어는 이와 같이 우리가 리터럴로 작성한 코드를 어떠한 규칙에 의해 해석하며, 그것에 해당되는 값을 평가하게 된다.

리터럴을 사용하여 data type을 구별

우리는 이러한 리터럴(아라비아 숫자, 알파벳, 한글, "", '', ., [ ], { } 등)을 사용하여 다양한 Data Type을 만들어낸다. 이는 자바스크립트 엔진은 코드가 실행되는 시점에, 우리가 코드에 작성한 리터럴을 평가하여, 해당 규칙에 맞는 값을 생성해주기 때문이다.
아래에는 자바스크립트 엔진이 리터럴을 통해 해석되어지는 DataType들이다.

|리터럴|예시|설명|
|------|---|---|
|정수 리터럴|100||
|부동소수점 리터럴|10.5||
|2,8,16진수 리터럴|0bXX..,0oXX..,0xXX...|b:binary, o:octal, x:hexadecimal|
|문자열 리터럴|"Hello World"||
|불리언 리터럴|true, false||
|null 리터럴|null||
|undefined 리터럴|undefined||
|객체 리터럴|{name:"KIM", "age":14}||
|배열 리터럴|[1,2,3]||
|함수 리터럴|function ( ){ } , ( )=>{ }||
|정규 표현식 리터럴|/[A-Z]/g||

표현식(Expression)

표현식이란 값으로 평가 될 수 있는 문(Statement)를 뜻한다.

문(Statement) :
프로그램을 구성하는 기본 단위이자 최소 실행단위이다. 선언문, 조건문, 반복문과 같은것들이 모두 문(Statement)이다. 프로그램에게 무언가 명령을 내릴수 있는 문장이라면, 모두 문이 될수 있다.

앞서 얘기했던 리터럴들도 자바스크립트 엔진에 의해 모두 값으로 평가받아지니, 모두 표현식이라고 할 수 있다.

꼭 값을 생성하지 않아도, 참조하는것 또한 표현식이다.

let a = 20 + 30;  // (1)

let b = a // (2)
console.log(b);  // (3)

위 예제의 흐름을 살펴보자.

  1. let a = 20 + 30;
    let 선언문에 의해 식별자 a,b는 환경레코드속에 변수를 가르키는 식별자로서 선언된다(변수 호이스팅). 이후, 변수 a에 값을 담기 위해 20 + 30 이란 연산을 평가하게 되고, 평가 결과 값인 50이 변수 a 속에 담기게된다.
  2. let b = a;
    이후, b의 초기화가 이루어지게 되고 이때, 변수 b는 변수 a가 가르키는 메모리 주소를 가르키게 된다.
  3. console.log(b);
    b에는 변수 a 가 가르키는 메모리 주소를 가르키고 있으므로, log에는 50이라는 값이 출력된다.

이 코드에는 이제 표현식이라고 할 수 있는 부분을 찾아보자.
앞서 말했듯, 표현식은, 값으로 평가 될수 있는 문을 뜻한다.
(1)에서 20 + 30 은 50 이라는 값을 생성하므로 표현식이다.
(2)에서 a는 50이라는 값을 참조하므로 표현식이다.
(3)에서 b또한 50이라는 값을 참조하게 되므로 표현식이라고 할수 있다.

위와 같이, 표현식인가 아닌가를 판단하는 기준은, 값으로서 반환되어지는가가 중요하다. 꼭 새로운 값을 만드는 것이 아니더라도, 기존의 값을 참조하여 반환하는 것 또한 표현식이라고 할 수 있다.

이는 곧, 문법적으로 값이 위치할 수 있는 모든 위치에는, 표현식이 위치 할 수 있다라고 생각해도 좋을것 같다.

보너스 : 함수 선언문은 표현식인가.

먼저 정답을 말하자면, 그렇지 않다. 이는 크롬 브라우저의 콘솔을 통해서 확인이 가능하다.

위와 같은 함수 표현식은 함수를 값으로서 반환하지만, 아래의 함수 선언문은 크롬 환경에서 완료 값이라고 부르는 undefined를 반환한다. 완료 값은 표현식의 평가 결과를 뜻하지 않으며, 그 대상 또한 표현식이 아니라는 뜻이 된다.


이와 같이 let과 같은 변수 선언문 또한 마찬가지다. 이들도 완료 값을 반환하므로 undefined를 출력하게 되며, 표현식이 위치할 수 있는곳에 작성할경우 문법적인 오류를 일으키게 된다.

하지만 다음과 같은 코드를 살펴보자

let foo = function bar (){console.log("hello")};

foo(); // "hello" 

위에서 살펴보았듯이, function 선언문은 말그대로 선언문이므로 표현식이 아니다. 이는 값으로서 다루어 질 수 없으며, 그러기 때문에 변수에 할당 되어질수 없어야한다.
하지만 위코드를 보면 bar함수는 마치 값인 것처럼 foo라는 변수에 값으로서 할당되어지고, foo는 해당 함수를 참조하여 foo()와 같이 해당 함수를 호출할수 있게 되었다. 함수 선언문은 표현식이 아닌데 어떻게 이런일이 일어 날수 있는걸까?
이는 자바스크립트 엔진의 예외처리 덕분에 일어난 일이다.
자바스크립트 엔진은 코드의 문맥에 따라, 함수 선언문을 표현식이 아닌것으로도, 표현식인것으로도 해석을 하게된다. 중요한것은 함수 선언문이 값으로서 표현될수 있는 위치에 있느냐이다.
함수 선언문은 피연산자의 위치에 있을때 엔진으로부터 표현식으로서 해석되어지고, 평가받게 된다.
실제로 표현식으로서 해석되어지는지는 함수의 이름없이 선언했을경우를 확인하면 확실해진다. ( 함수 선언식은 함수이름을 반드시 할당해야하는 규칙이 있다. )

위와 같이 피연산자에 위치한 함수 선언식은 오류 없이 표현식으로서 작동하게 된다.

이와같이 함수 선언문또한 변수에 할당할수도, 인자로 전달 할수도, 값으로 취급되어 질수있게되고,
초반에 언급했듯 JavaScript의 '모든 함수는 일급 함수이다' 라는 말이 성립하게 된다.

let f1 = function (){} // 변수에 할당할수도

let f2 = (f) => {console.log(f)}

f2(f1) // 인자로 전달 할수도,

(function f3(){console.log("Hi")})
// 즉시실행함수와같은 값으로서도 사용 가능하다.

참고문헌

Javascript Deep Dive 5장,12장

profile
안녕하세요. 개발자 지망생입니다.

0개의 댓글