자바스크립트에서 표현식이란 어떤 값으로 평가되는 구절이다.
프로그램에 포함된 상수도 단순하지만 표현식이다.
변수 이름 역시 표현식이며 그 변수에 할당된 값으로 평가된다.
복잡한 표현식은 단순한 표현식의 조합으로 구성된다.
단순한 표현식을 조합해 복잡한 표현식을 만들 때는 대부분 연산자를 사용한다.
연산자는 피연산자의 값을 어떤 형태로 조합해 새 값으로 평가한다.
값으로 "평가"된다 대신 연산자가 값을 "반환"한다 라고 표현할 때도 있다.
가장 단순한 표현식을 기본 표현식이라고 부른다.
이는 단독으로 존재하며 자신보다 더 단순한 표현식을 포함하지 않는다.
자바스크립트의 기본 표현식은 상수나 리터럴 값, 일부 키워드, 변수 참조가 있다.
1.23 // 숫자 리터럴
"hello" // 문자열 리터럴
/pattern/ // 정규 표현식 리터럴
true // 불 true로 평가된다.
false // 불 false로 평가된다.
null // null로 평가된다.
this // "현재" 객체로 평가된다.
this
는 다른 키워드와 달리 일정한 값이 아니며 프로그램에서 사용한 위치에 따라 다른 값으로 평가된다.
this
키워드는 객체 지향 프로그래밍에서 사용되며 메서드 바디에서 this
는 해당 메서드를 호출한 객체로 평가된다.
i // 변수 i 값으로 평가
sum // 변수 sum 값으로 평가
undefined // 전역 객체의 "undefined" 프로퍼티 값
자바스크립트는 프로그램에 있는 식별자를 변수, 상수, 또는 전역 객체의 프로퍼티라고 가정하고 그 값을 찾는다.
그런 이름의 변수가 존재하지 않는다면 존재하지 않는 변수를 평가하려는 시도이므로 ReferenceError가 일어난다.
객체와 배열의 초기화 표현식은 그 값이 새로 생성된 객체나 배열인 표현식이다.
이런 초기화 표현식을 객체 리터럴이나 배열 리터럴이라고 부리기도 한다.
하지만 리터럴과 달리 초기화 표현식은 프로퍼티와 요소 값을 지정하는 다양한 하위 표현식으로 구성되므로 기본 표현식은 아니다.
배열 초기화 표현식은 대괄호 안에 콤마로 구분된 리스트를 쓰는 형태의 표현식이다.
배열 초기화 표현식의 값은 새로 생성된 배열이다.
새 배열의 요소는 콤마로 구분된 표현식들의 값으로 초기화 된다.
[] // 빈 배열. 대괄호 안에 표현식이 없으면 요소가 없다는 의미.
[1 + 2, 3 + 4] // 요소가 두 개인 배열.
배열 초기화 표현식 내부의 요소 표현식 역시 배열 초기화 표현식이 될 수 있다.
즉, 이 표현식은 중첩된 배열을 반환한다.
let matrix = [[1, 2, 3], [4, 5, 6]];
배열 초기화 표현식 내의 요소 표현식은 배열 초기화 표현식을 평가할 때마다 평가된다.
즉, 배열 초기화 표현식을 평가할 때마다 결과가 달라질 수도 있다.
배열 리터럴에서 콤마 사이의 값을 생략하면 정의되지 않은 요소가 그 자리에 들어간다.
// 다섯개의 요소 중 세개는 정의되지 않음
let sparseArrat = [1,,,, 5];
배열 초기화 표현식 내부의 마지막 표현식 다음에 콤마가 단 하나 있으면 정의되지 않은 요소가 만들어지지는 않는다. 하지만 그 마지막 표현식 다음의 인덱스로 배열에 접근하는 표현식은 undefined
로 평가된다.
객체 초기화 표현식은 배열 초기화 표현식과 비슷하지만, 대괄호 대신 중괄호를 쓰고 각 하위 표현식은 프로퍼티 이름과 콜론으로 시작한다.
let p = {x : 2.3, y : -1.2}; // 프로퍼티가 두 개 있는 객체
let q = {}; // 프러퍼티가 없는 빈 객체
q.x = 2.3; q.y = -1.2; // q의 프로퍼티는 p의 프로퍼티와 같다.
// 객체 리터랄의 중첩
let rectangle = {
upperLeft : {x : 2, y : 2},
lowerRight : {x : 4, y : 5}
};
함수 정의 표현식은 함수를 정의하며 그 값은 함수이다. 함수 정의 표현식을 "함수 리터럴"이라고도 한다.
함수 정의 표현식은 일반적으로 function
키워드로 시작하고 괄호 안에 0개 이상의 식별자(배개변수 이름)을 쓴 다음,
중괄호 안에 자바스크립트 코드(함수 바디)를 쓰는 형태이다.
let square = function(x) { return x * x; };
함수 정의 표현식에 함수 이름을 쓸 수도 있고, 함수는 함수 선언을 써서 정의할 수도 있다.
프로퍼티 접근 표현식은 객체 프로퍼티나 배열 요소의 값으로 평가된다.
자바스크립트에는 두 가지 프로퍼티 접근 문법이 있다.
expression.identifier
expression[expression]
첫 번째 스타일은 표현식 뒤에 마침표를 쓰고 그 뒤에 식별자를 쓰는 것이다.
표현식은 객체를 나타내고 식별자는 원하는 프로퍼티 이름이다.
두 번째 스타일은 표현식(객체나 배열) 뒤에 대괄호를 쓰고 그 안에 다른 표현식을 쓰는 형태이다.
두 번째 표현식은 프로퍼티 이름이나 배열 요소 인덱스이다.
let o = {x : 1, y : {z : 3}}; // 객체
let a = [o, 4, [5, 6]]; // 객체를 담고 있는 배열
o.x // 1; 표현식 o의 프로퍼티 x
o.y.z // 3; 표현식 o.y의 프로퍼티 z
o["x"] // 1; 객체 o의 프로퍼티
a[1] // 4; 표현식 a의 인덱스 1에 있는 요소
a[2]["1"] // 6; 표현식 a[2]의 인덱스 1에 있는 요소
a[0].x // 1; 표현식 a[0]의 프로퍼티 x
어떤 스타일의 프로퍼티 접근 표현식을 쓰든 .
이나 [
앞에 있는 표현식을 첫 번째로 평가한다.
그 값이 null
이나 undefined
이면 이 둘은프로퍼티를 가질 수 없는 값이므로 표현식은 TypeError
을 일으킨다.
객체 표현식 다음에 점과 식별자가 있으면 그 식별자가 이름인 프로퍼티를 찾고, 그 프로퍼티의 값이 표현식의 전체적인 값이 된다.
객체 표현식 다음에 대괄호가 있고 그 안에 다른 표현식이 있으면 두 번째 표현식을 평가하고 문자열로 반환한다.
표현식의 전체적인 값은 그 문자열이 이름인 프로퍼티의 값이 된다.
어느쪽이든, 그런 이름의 프로퍼티가 존재하지 않는다면 프로퍼티 접근 표현식의 값은 undefined
이다.
ES2020에서 새로운 프로퍼티 접근 표현식 두 가지를 추가했다.
expression ?. identifier
expression ?. [expression]
자바스크립트에서 프로퍼티를 가질 수 없는 값은 null
과 undefined
뿐이다.
마침표나 대괄호를 사용하는 일반적인 프로퍼티 접근 표현식에는 왼쪽에 있는 표현식이 null
이나 undefinded
로 평가될 때 TypeError
가 일어난다.
?.
과 ?.[]
문법을 이용해 에러를 막을 수 있다.
a.?b
: a
가 null
이거나 undefined
라면 이 표현식은 프로퍼티 b
에 접근하려는 시도 없이 undefined
로 평가된다.
a
가 다른 값이라면 a.?b
는 a.b
처럼 평가된다. (a
에 b
프로퍼티가 없으면 undefined
로 평가)
이런 형태의 프로퍼티 접근 표현식을 때때로 '옵션 체인'이라고 부른다.
let a = { b : null };
a.b?.c.d // undefined
a
는 객체이므로 a.b
는 유효한 프로퍼티 접근 표현식이다.
하지만 a.b
의 값은 null
이므로 a.b.c
는 TypeError
를 일으킨다.
.
대신 ?.
를 사용하면 TypeError
가 일어나지 않고 a.b?.c
는 undefined
로 평가된다.
따라서 (a.b?.c).d
는 TypeError
를 일으킨다. 값이 undefined
인 프로퍼티에 접근하는 표현식이기 때문이다.
하지만a.b?.c.d
는 undefined
로 평가되며 에러를 일으키지 않는다.
이는 ?.
을 사용한 프로퍼티 접근이 '단축 평가'이기 때문이다.
?.
의 왼쪽에 있는 하위 표현식이 null
이나 undefined
로 평가되면 더는 프로퍼티에 접근하려 시도하지 않고 전체 표현식을 즉시 undefined
로 평가한다.
[]
대신 ?.[]
를 사용하는 조건부 프로퍼티 접근도 있다.
a?.[b][c]
표현식에서 a
의 값이 null
이나 undefined
라면 전체 표현식이 즉시 undefined
로 평가되며 b
와 c
하위 표현식은 평가되지 않는다. b
와 c
표현식에 다른 부수적인 효과가 있더라도 a
가 정의되지 않은 경우에는 나타나지 않는다.
let a;
let index = 0;
try {
a[index++]; // TypeError
} catch(e) {
index // 1; TypeError가 일어나기 전 증가
}
a?.[index++] // undefined; a가 정의되지 않음
index // 1; ?.[]는 단축 평가이므로 index는 증가하지 않음
a[index++] // TypeErrpr 정의되지 않은 a
호출 표현식은 함수나 메서드를 호출(실행)하는 문법이다.
이 표현식은 호출할 함수로 평가되는 함수 표현식으로 시작한다.
함수 표현식 다음에 여는 괄호를 쓰고, 콤마로 구분된 0개 이상의 함수 인자 표현식 리스트를 쓰고, 닫는 괄호로 끝난다.
f(0)
Math.max(x, y, z)
a.sort()
호출 표현식을 평가할 때는 첫 번째로 함수 표현식을 평가하고, 다음으로 함수 인자 표현식을 평가해 인자 값 리스트를 만든다.
함수 표현식의 값이 함수가 아니라면 TypeError
가 일어난다. 그리고 인자 값을 함수를 정의할 때 지정된 함수 매개변수에 순서대로 할당한 다음, 함수 바디를 실행한다.
함수가 return
문을 사용해 값을 반환한다면 그 값이 호출표현식의 값이다. 그렇지 않다면 호출 표현식의 값은 undefined
이다.
호출 표현식 제일 앞에 있는 표현식이 프로퍼티 접근 표현식이라면 이 호출은 메서드 호출이라고 한다.
메서드 호출에서 프로퍼티 접근 대상인 객체 또는 배열은 함수 바디가 실행되는 동안 this
키워드의 값이 된다.
이를 통해 함수가 자신이 속한 객체에 작용하는 객체 지향 프로그래밍 패러다임을 자바스크립트에서도 사용할 수 있다.
ES2020에서는 ()
대신 ?.()
를 통해 함수를 호출할 수 있다.
일반적으로 함수를 호출할 때 괄호 왼쪽의 표현식이 null
이나 undefined
, 기타 함수가 아닌 것으로 평가될 때는 TypeError
가 일어난다.
?.()
호출 문법을 사용하면 ?.
왼쪽에 있는 표현식이 null
이나 undefined
로 평가될 때는 호출 표현식 전체를 undefined
로 평가하며 예외는 일어나지 않는다.
배열에는 sort()
메서드가 있고 이 메서드는 배열 요소의 정렬 순서를 정의하는 함수 인자를 선택 사항으로 받을 수 있다.
ES2019 이전에는 sort()
처럼 선택 사항인 함수 인자를 받는 메서드를 작성할 때는 일반적으로 아래와 같이 if
문을 써서 선택 사항인 인자가 전달됐는지 확인해야 했다.
function square(x, log) {
if (log) {
log(x);
}
return x * x;
}
ES2020의 조건부 호출 문법을 쓰면 ?.()
를 사용해 함수를 호출하기만 하면 된다.
호출할 값이 존재할 때만 호출하며 에러는 일어나지 않는다.
function square(x, log) {
log?.(x);
return x * x;
}
하지만 ?.()
는 왼쪽에 있는 것이 null
이나 undefined
인지만 체크한다.
이 연산자는 값이 실제로 함수인지까지 체크하지 않는다.
조건부 프로퍼티 접근 표현식과 마찬가지로 ?.()
를 사용한 함수 호출 역시 단축 평가이다.
?.
왼쪽에 있는 값이 null
이나 undefined
라면 괄호 안에 있는 함수 인자 표현식은 평가되지 않는다.
let f = null, x = 0;
try {
f(x++); // f가 null이면 TypeError
} catch(e) {
x // 1; x는 예외가 일어나기 전 증가
}
f?.(x++) // undefined; f는 null이지만 예외가 일어나지 않음
x // 1; 단축 평가 이므로 x는 증가하지 않음
?.()
를 사용하는 조건부 호출 표현식은 메서드에서도 함수와 똑같이 동작한다.
하지만 메서드 호출에는 반드시 프로퍼티 접근이 수반됨.
o.m() // 일반적인 프로퍼티 접근, 일반적인 호출
o?.m() // 조건부 프로퍼티 접근, 일반적인 호출
o.m?.() // 일반적인 프로퍼티 접근, 조건부 호출
첫 번째 표현식에서 o
는 반드시 객체여야 하고, m
프로퍼티가 있어야 하며, 프로퍼티 값은 반드시 함수.
두 번째 표현식에서 o
가 null
이나 undefined
라면 전체 표현식은 undefined
로 평가.
o
가 null
이나 undefined
이 아니라면 반드시 m
프로퍼티가 있어야 하고 그 값은 반드시 함수.
세 번째 표현식에서 o
는 반드시 null
이나 undefined
가 아니어야 한다.
o
에 m
프로퍼티가 없거나 그 프로퍼티 값이 null
이라면 전체 표현식이 undefined
로 평가됨.
객체 생성 표현식은 객체를 생성하고 함수(생성자)를 호출해 객체 프로퍼티를 초기화한다.
객체 생성 표현식은 호출 표현식과 같지만, 그 앞에 new
키워드를 붙인다.
new Object()
new Point(2, 3)
// 객체 생성 표현식에서 생성자 함수에 전달할 인자가 없다면 빈 괄호는 생략 가능
new Object()
new Date
객체 생성 표현식의 값은 새로 생성된 객체이다.