본문 바로가기
Javascript

JavaScript - Expression vs Statement(표현식과 문장)

by Su1993 2020. 9. 16.
반응형

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

 

  • Expression
  • Statement

표현식(Expression)은 문장(Statement)처럼 동작할 수 있지만 문장(Statement)은 표현식(Expression)처럼 동작할 수 없다.

 


Expression(표현식)

표현식은 값을 산출해내는 코드를 의미한다. 값이 도출되기 때문에 함수의 인자로 들어갈 수 있다.

1;
5 + 5;
'Hello world';
exFunc('a','b');
exam;

 

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

console.log(true && 1 * 5) // 5

 

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

const a = 1; // 이건 statement이다. a는 상태이다.

a * 2 // 표현식

a + 1 // 표현식

a - 1 // 표현식

console.log(a); // 1

 

 

함수 호출은 표현식이지만 함수는 값을 변화시키는 문장(Statement)을 포함할 수 있다. 

const test = test() => {
  a = 11;
}

 

 

test 내부의 test() 함수는 undefined나 어떤 다른 값을 반환할 수 있는 표현식이다. 위처럼 작성한다면 test를 호출하는 것이 표현식일지라도 함수를 호출하면 결국 상태(state)가 바뀌게 된다. 그래서 test함수를 더 나은 방법으로 작성하면 문장(Statement)은 다음과 같다.

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

testResult = test()

 

또는

 

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

testResult = test(10)

 

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

 


문장(Statements)

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

자바스크립트의 문장(Statements)은 다음과 같다.

 

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

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

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

function a (test) {
  return test.name;
}

 

함수 표현식은 표현식이다.(익명함수라 부르는 것들)

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

 

네임드 함수 표현식은 익명함수처럼 표현식이다. 하지만 함수에 이름이 붙어있다.

console.log(a(function myName(){} )); // "myName"

 

자바스크립트에서 값이 들어올 곳에 함수를 선언할 때마다, 자바스크립트는 그것을 값으로 다루려 한다. 만일 그 함수가 값으로 사용될 수 없다면 에러가 발생한다. 반면에 스크립트, 모듈, 블록 문장(자바스크립트에서 값이 들어가는 곳이 아닌 위치에 있는)의 전역 단계(Global level)에 함수를 선언하는 것은 결과적으로 함수 선언이다.

 

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

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

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

function a() {
  return function b() {} // 네임드 함수 표현식
}

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

function a () {
  return function b() {
    function c() {} // 블록의 가장 상위 레벨, 함수 선언
  }
}

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

 

 


표현식 문장(Expression Statements)

표현식(Expressions)을 표현식 문장(Expression Statements)으로 바꿀 수 있다. 마지막에 세미콜론만 추가하면 된다.

1+1 // 이 자체로는 표현식

a(1+1) // 그래서 어디든 값이 들어가야 할 곳에 사용가능

true ? 1+1 : 2+2

function a() {return 1+1}

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

 


세미콜론 vs 콤마 연산자

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

const a; function b() {}; const c = 1;

 

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

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

console.log((1, 6/3, function() {})) // function() {}

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

 

자바스크립트 엔진에 값을 전달할 때, 값이 들어가야 할 곳에 괄호'()'를 통해 값을 전달해야 한다. 괄호가 없으면 각각을 console.log의 인자로 보낸다.

 

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

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

 


IIFEs(Immediately Invoked Function Expression(즉시 호출되는 함수 표현식))

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

function() {} // 에러

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

 

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

(function() {
  // do something
})()
(function () {
  console.log("익명함수 호출");
})() // "익명함수 호출"

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

console.log((function() {
  return 2;
})()) // 2

// 인자를 넘길 수도 있다.
(function(a) {
  return a;
})("test"); // "test"

 


Object literal vs Block Statement(오브젝트 리터럴과 블록 문장)

r: 1+1 // 유효

test()

const test = () => {}

 

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

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

 

라벨을 표현식이나 표현식 문장에 붙일 수 있다.

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

 

{}와 같은 괄호는 문장과 표현식 문장들을 그룹화하는데 도움을 준다.

{let a = "b"; func(); 1+1} // 2

 

브라우저 콘솔에 넣으면 2를 반환하고 console.log(a);를 확인해보면 b를 반환한다. 이것을 블록 문장이라고 부른다. 오브젝트 리터럴과는 다르다.

console.log({a: "b"}); // {a: "b"} 오브젝트 리터럴

console.log({let a = "b", func(), 1+1}) // SyntaxError 블록 문장

const test = {let a = "b", func(), 1+1} // SyntaxError 블록 문장

 

console.log는 문장(statement)을 인자로 받아들일 수 없는 함수이므로 블록 문장을 값이나 표현식으로 사용할 수 없다. 하지만 오브젝트 리터럴은 인자로 받아들일 수 있다.

{} + 1 // 1

{1} + 2 // 1

{1+1} + 2 // 2

{1+1} - 2 // 2

 

문장(statement)은 값으로 쓰일 수 없으므로 어느 것도 반환하도록 되어있지 않다. 그래서 자바스크립트는 Error 대신 + 연산자의 피연산자를 숫자나 문자열로 바꾼다. 여기서 바꿀 수 없는 값이라면 이때 Error를 내보낸다. 블록 문장(block statements)에서 무엇이 반환되던지 그것은 암묵적으로 0으로 강제 형 변환되어 피연산자로 사용된다.

반응형

댓글