[자바스크립트 개발자라면 알아야 할 33가지 개념] #7 표현식(Expression)과 문자(Statement) (번역)

이윤우·2023년 4월 13일
0

JavaScript

목록 보기
25/34
post-thumbnail

자바스크립트에는 대표적인 2가지 문법적 카테고리가 있습니다.

  1. Statement (문장)
  2. Expressions (표현식)

표현식은 문장처럼 동작할 수 있기 때문에 이 둘을 구분하는 것은 중요합니다. 그리고 이것이 표현문이 존재하는 이유기도 하죠. 하지만 반대로 봤을 때 문장은 표현식처럼 동작할 수 없습니다.

표현식(Expressions)

표현식은 값을 만들어낸다.

표현식은 값 하나로 귀결되는 자바스크립트 코드 조각입니다. 표현식은 우리가 원하는만큼 길어질 수 있지만 언제나 동일한 값이 나오진 않죠.

2 + 2 * 3 / 2
(Math.random() * (100-20)) + 20

true && functionCall()

위의 모든 코드는 표현식입니다. 그리고 표현식은 자바스크립트 코드 중 값이 들어가는 곳이면 어디에나 넣을 수 있습니다. 그래서 아래 console.log의 인자는 콘솔이 로깅될 때 하나의 값으로 변합니다.

console.log(true && 2 * 9) // 18

표현식은 반드시 상태(State)를 바꿀 필요는 없다.

예를 들면,

const assignedVariable = 2; // 이건 문장입니다.

assignedVariable * 4 // 표현식입니다.

assignedVariable * 10 // 표현식입니다.

assignedVariable - 10 // 표현식입니다.

console.log(assignedVariable) // 2

위의 짤막한 코드의 모든 표현식에도 불구하고 assignedVariable의 값은 여전히 2입니다. 그래서 왜 이 섹션의 제목에 반드시라는 단어를 등장시켰냐면 함수 표현은 표현식이기 때문입니다. 하지만 함수는 값을 변화시키는 문장을 포함할 수 있습니다. foo 내부의 foo() 함수는 undefined나 어떤 다른 값을 반환할 수 있는 표현식입니다. 하지만 만일 foo가 다음과 같이 작성됐다면,

const foo = foo() => {
	assignedValue = 14
}

그 땐, foo를 호출하는 것은 표현식일지라도, 함수를 호출하면 결국 상태가 바뀌게 됩니다. 그래서 foo 함수를 더 나은 방법으로 재작성하려면 문장은 다음과 같을 것입니다.

const foo = foo() => {
	return 14; 
}

assignedVariable = foo()

아니면 더 나은 방법으로

const foo = foo (n) => {
	return n
}

assignedVariable = foo(14)

이 방법이 가독성이 더 좋고, 어딘가에 끼워 넣기 좋으며 표현식과 문장 사이에서 확연히 구분이 됩니다. 이것이 선언적이고 함수적인 자바스크립트의 기반입니다.

문장(Statements)

함수형 프로그래밍의 관점에서 문장은 골치덩어리입니다. 기본적으로 문장은 무언가 수행합니다.

자바스크립트에서 문장은 값이 들어와야 할 곳에 들어갈 수 없습니다. 그래서 그들은 함수의 인자로도, 대입 연산의 값으로도, 연산자의 피연산자로도 사용될 수 없습니다.

foo(if () {return 2})

자바스크립트의 문장은 다음과 같습니다.

  1. if
  2. if-else
  3. while
  4. do-while
  5. for
  6. switch
  7. for-in
  8. with (deprecated)
  9. debugger
  10. variable declaration

브라우저의 콘솔에 다음과 같이 코드를 치고 엔터를 치면 어떻게 될까요?

if (true) {9 + 9}

아마 18이 리턴된 것이 보일 것입니다. 하지만 우리는 이 결과를 표현식처럼 사용하거나 자바스크립트 코드내에 값이 들어갈 어딘가에 넣을 수 없습니다. 이 결과는 이상합니다. 우리는 문장이 아무것도 반환하지 않을 것이라 예상했기 때문일 겁니다. 우리가 반환된 값을 이용할 수 없으면 문장이 값을 반환하는 것은 아무런 의미가 없습니다. 이게 바로 자바스크립티입니다. 이상합니다.

함수 선언, 함수 표현식 그리고 네임드(Named) 함수 표현식

함수 선언은 문장입니다.

function foo(func) {
	return func.name
}

함수 표현식은 표현식입니다. 바로 우리가 익명 함수라 부르는 것들입니다.

console.log(foo(function () {}))

네입드 함수 표현식은 표현식입니다. 익명 함수처럼요. 하지만 이 함수는 이름이 붙었습니다.

console.log(foo(function myName() {}))

표현식으로서의 함수와 선언으로서의 함수의 구분은 아래의 내용을 이해하는 것으로 요약됩니다.
우리가 자바스크립트에서 값이 들어올 곳이 함수를 선언할 때마다, 자바스크립트는 그것을 값으로 다루려 할 것입니다. 만일 그 함수가 값으로 사용될 수 없다면, 에러가 발생할 것입니다.
반면에 스크립트, 모듈, 블록 문장(자바스크립트에서 값이 들어가는 곳이 아닌 위치에 있는)의 전역 단계에 함수를 선언하는 것은 결과적으로 함수선언입니다.

if () {
  function foo () {} // 블록의 가장 상위 레벨, 함수 선언
}

function foo () {} // 전역 레벨, 함수 선언

function foo () {
  function bar () {} // 블록의 가장 상위 레벨, 함수 선언
}

function foo () {
  return function bar () {} // 네임드 함수 표현식  
}

foo(function () {}) // 익명 함수 표현식

function foo () {
  return function bar () {
    function baz () {} // 블록의 가장 상위 레벨, 함수 선언  
  }
}

function () {} // 문법 에러: 함수 문장(statement)은 이름이 필요합니다.

표현식을 문장으로 바꾸기: 표현식 문장

여태까지 자바스크립트에 대한 것중 어느것 하나라도 간단하고 직관적인 것이 있었나요?
우리는 표현식을 표현식 문장으로 바꿀 수 있습니다. 단지 뒤에 세미콜론만 추가하면 됩니다.

2 + 2 // 그 자체로는 표현식입니다.
2 + 2; // 표현식 문장

세미콜론 vs 콤마 연산자

세미 콜론을 붙이면, 여러 줄의 문장을 하나의 줄에 넣을 수 있습니다.

const a; function foo () {}; const b = 2;

콤마 연산자는 우리가 여러 개의 표현식을 연결할 수 있도록 도와줍니다. 반환은 마지막 표현식만 반환합니다.

console.log((1 + 2, 3, 4))

IIFEs (즉시 실행 함수 표현식)

익명 함수는 표현식으로 쓰일 수 있습니다. 자바스크립트에서 값이 들어갈 곳에 쓰일 수 있다면, 우리가 만약 자바스크립트에서 값이 들어갈 곳에 괄호를 쓸 수 있다면 우리는 익명 함수를 값으로 넘길 수 있다는 것을 의미합니다.

function () {}

위의 코드는 유효하지 않은 반면에 아래의 코드는 유효합니다.

(function () {})

만일 익명 함수를 괄호 속에 넣는다면 즉시 같은 익명 함수를 리턴합니다. 이 말은 루리가 바로 이 함수를 불러올 수 있다는 것입니다.

(function () {
	// do something
})()

오브젝트 리터럴 vs 블록 문장

r: 2 + 2 // 유효함
foo()
const foo = () => {}

글로벌 스코프에 위치한 위의 문장들은 유효한 자바스크립트로 변경되어 실행됩니다. r 은 label이라 불리는 것입니다. breaking loops를 구성할 때 유용합니다. 예제는 다음과 같습니다.

loop: {
	for (const i = 0; i < 2; i++) {
    	for (const j = 0; j < 2; j++){
        	break loop; // 바깥 루프를 중단하여 전체 루프를 중단합니다.
        }
    }
}

라벨을 어떤 표현식이나 표현식 문장에 붙일 수도 있습니다.
다음의 예제를 보고, 라벨을 만드는 것이 변수를 만드는 건 아니라는 것을 알 수 있습니다.

lab: function a () {}
console.log(lab) // ReferenceError: lab is not defined

{}와 같은 괄호는 문장과 표현식 문장들을 그룹화하는데 도움을 줍니다.
다음과 같이 작성할 수 있습니다.

{var a = 'b'; function(); 2 + 2} // 4

위의 내용을 브라우저 콘솔에 붙여넣기 하면, 4를 반환할 것입니다. 그리고 console.log(a)를 쳐보면 b를 반환합니다. 이것을 블록 문장이라고 불러도 됩니다. 우리에게 익순한 오브젝트 리터럴과는 다른 것입니다.

console.log({a: 'b'}); // {a: 'b'}

console.log({var a = 'b', function(), 2 + 2}) // SyntaxError

const obj = {var a = 'b', function(), 2 + 2} // SyntaxError

블록 문장을 값이나 표현식으로 사용할 수는 없습니다. console.log는 문장을 인자로 받아들일 수 없는 함수니까요. 하지만 오브젝트 리터럴은 인자로 받아들일 수 있습니다. 위의 설명했던 모든 것들을 이해하셨길 바랍니다.

0개의 댓글