표현식(Expression)과 문장(Statement)

fromzoo·2020년 12월 10일
0

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

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

표현식은 문장처럼 동작할 수 있다 -> 때문에 둘은 구분하는 것은 중요하다.
그리고 이것이 표현문이 존재하는 이유다.

하지만 반대로 문자은 표현식처럼 동작할 수 없다.

표현식(Expressions)

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

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

2 + 2 * 3 / 2

(Math.random() * (100-20)) + 20

functionCall()

window.history ? useHistory() : noHistoryFallback()

1+1, 2+2, 3+3

declaredVariable

true && functionCall()

true && declaredVariable

위의 모든 코드는 표현식이다.
그리고 표현식은 자바스크립트 코드 중 값이 들어가는 곳이면 어디에나 넣을 수 있다.

그래서 아래 console.log의 인자는 콘솔이 로깅될 때 하나의 값으로 변한다.

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

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

예를들면,

const assignedVariable = 2; // 이건 문장(Statement)입니다. assignedVariable은 상태입니다.

assignedVariable * 4 // 표현식(Expression)입니다.

assignedVariable * 10 // 표현식(Expression)입니다.

assignedVariable - 10 // 표현식(Expression)입니다.

console.log(assignedVariable) // 2

위의 짤막한 코드의 모든 표현식에도 불구하고 assignedVariable의 값은 여전히 2다.

그래서 이 섹션의 제목에 왜 반드시라는 단어를 등장시켰냐면 함수 호출은 표현식이기 때문이다.

하지만 함수는 값을 변화시키는 문장을 포함할 수 있다.

foo내부의 foo()함수는 undefined 나 어떤 다른 값을 반환할 수 있는 표현식이다.
하지만 만일 foo가 다음과 같이 작성됐다면,

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

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

함수는 표현식 , 표현식은 상태를 반드시 바꿀 수 없다. - > 함내 내부는 값을 변화시키는 문장을 포함할 수 있다???

const foo = foo () => {
	return 14 // 가독성을 위한 명시적 반환
}

assignedVariable = foo()

아니면 더 나은 방법으로

const foo = foo (n) => {
	return n // 가독성을 위한 명시적 반환
}

assignedVariable = foo(14)

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

문장 (Statements)

함수형 프로그래밍의 관점에서 문장은 골치덩어리

기본적으로 문장은 무언가 수행한다.

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

foo(if () {return 2}) 

자바스크립트의 문장(statement)은 다음과 같다.
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

브라우저 콘솔에 다음과 같은 코드를 치고 엔터를 치면??

i( true ) {9+9} 

아마 18이 리턴된 것이 보일 것이다.
하지만 우리는 이 결과를 표현식처럼 사용하거나 자바스크립트 코드 내에 값이 들어갈 어딘가에 넣을 수 없다.

이 결과는 이상하다.

우리는 문장이 아무것도 반환하지 않을 것이라 예상했기 떄문이다.

우리가 반환된 값을 이용할 수 없으면 문장이 값을 반환하는 것은 아무런 의미가 없다. 이게 바로 자바스크립트다.

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

함수 선언은 문장(statement)이다.

function foo (func) {
	return func.name;
}

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

console.log(foo(function(){})); //""

네임드 함수 표현식은 표현식이다. 익명함수처럼

하지만 이함수는 이름이 붙었다.

console.log(foo(function myName () {} )); // "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; // expression statement
foo(); // expression statement

우리는 표현식을 표현식 문장으로 바꿀수 있다.
단지 뒤에 세미콜론만 추가하면 된다.

2+2자체는 표현식이다.
하지만 줄 자체는 표현식 문장이다.

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

foo(2+2) // 그래서 어디든 값이 들어가야 할 곳에서 사용할 수 있죠.

true ? 2+2 : 1 + 1

function foo () {return 2+2}

2+2; // 표현식 문장(Expression Statements)
foo(2+2;) // 문법 에러(Syntax Error)

세미콜론 vs 콤마연산자

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

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

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

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

console.log( (2, 9/3, function () {}) ) //function () {}

console.log( (3, true ? 2+2 : 1+1) ) // 4

알아두면 좋은것 : 자바스크립트 엔진에게 값을 전달할때, 값이 들어가야할 곳에 ()를 통해 값을 전달하자. 괄호가 없으면 각각을 console.log의 인자로 보낸다.

function foo () {return 1, 2, 3, 4}
foo() // 4

모든 표현식은 왼쪽에서 오른쪽으로 계산된다. 그리고 마지막 것이 리턴된다.

IIFE 즉시 호출되는 함수 표현식

익명함수는 표현식으로 쓰일 수 있다.

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

function() {}

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

아래의 코드는 유효하다.

(function() {}) // function() {} 를 리턴한다.

만일 익명 함수를 괄호 속에 넣는다면 즉시 같은 익명함수를 리턴한다.

이말은 우리가 바로 이 함수를 불러올 수 있다는 것이다.

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

그래서 다음과 같은 것도 가능하다.

(function () {
	console.log('익명함수 즉시 호출');
})() // '익명함수 즉시 호출'

(function(){
	return 3;
})() // 3

console.log(
	(function(){
		return 3
	})()
) // 3

// 인자를 넘길 수도 있다.
(function(a){
	return a;
})('저는 인자입니다.') // 저는 인자입니다.

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

주 : 리터럴이란 값 그자체를 의미한다.
사이드노트 : 다음에 나오는 코드들은 유효한 자바스크립트다.

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

글로벌 스코프에 위치한 위의 문장(Statement)들은 유효한 자바스크립트로 변경되어 실행된다. r은 label이라 불리는 것이다. breaking loops를 구성할때 유용하다.

예제

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

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

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

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

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

위의 내용을 브라우저 콘솔에 붙여넣기 하면, 4를 반환할 것이다.

그리고 console.log(a)쳐보면 b를 반환한다.이것을 블록문장이라고 불러도 된다.

우리에게 익숙한 오브젝트 리터럴과는 다른것

console.log({a:'b'}) // {a:'b'} 오브젝트 리터럴
console.log({var a = 'b', func(),2+2}) //SyntaxError 블록문장
const obj = {var a = 'b', func(), 2+2} //SyntaxError 블록문장 

블록 문장을 값이나 표현식으로 사용할 수는 없다.

console.log는 문장을 인자로 받아들일 수 없는 함수

하지만 오브젝트 리터럴은 인자로 받아들일 수 있다.

{} + 1 // 1

{2} + 2 // 2

{2+2} + 3 // 3

{2+2} - 3 // -3

아마 위의 코드들이 문번에러나 1,4,7과 같은 숫자를 각각 리턴한다고 예측했을 수도 있다.

문장은 어느것도 반환하도록 되어있지 않는다.

왜냐하면 값으로 쓰일 수 없기 때문이다.

그래서 자바스크립트는 error를 내보내지 않는 대신에 + 연산자의 피연산자를 숫자나 문자열로 바꾼다.

만일 바꿀 수 없는 값이라면 에러를 내보낸다.

블록문장에서 무엇이 반환되던디 그것은 암묵적으로 0으로 강제 형변환되어 피연산자로 사용된다.

Javascript 내에서 Expressions, Statements, Expression Statements에 대해서는 이정도만 알면 된다.

🔍 출처 블로그
자바스크립트 개발자라면 알아야 할 33가지 개념 #7 표현식(Expression)과 문장(Statement) (번역)

profile
프론트엔드 주니어 개발자 🚀

0개의 댓글