자바스크립트에서는 대표적인 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으로 강제 형 변환되어 피연산자로 사용된다.
'Javascript' 카테고리의 다른 글
JavaScript - Message Queue and Event Loop (0) | 2020.09.18 |
---|---|
JavaScript - IIFE, Modules and Namespaces (0) | 2020.09.18 |
JavaScript - Function, Block, Lexical Scope (0) | 2020.09.15 |
JavaScript - == vs === vs Typeof (0) | 2020.09.14 |
JavaScript - Type Coercion(형 변환) (0) | 2020.09.08 |
댓글