동그란 도그린
[자바스크립트 완벽 가이드🦏] 4장 : 표현식과 연산자 본문
📍 표현식이란?
- 어떤 값으로 평가되는 구절
📍 기본 표현식
- 가장 단순한 표현식
- 상수, 리터럴 값, 일부 키워드, 변수 참조 등이 있음
true // 불 true로 평가
false // 불 false로 평가
null // null로 평가
this // '현재' 객체로 평가 (일정한 값이 아니며, 사용한 위치에 따라 다른 값으로 평가)
📍 객체와 배열 초기화 배열식
- 값이 새로 생성된 객체나 배열인 표현식 (객체 리터럴 / 배열 리터럴)
- 배열 초기화 표현식
- 대괄호 안에 콤마로 구분된 리스트를 쓰는 형태
- 배열 초기화 표현식 내부의 요소 표현식도 배열 초기화 표현식이 될 수 있음, 이 표현식은 배열 초기화 표현식을 평가할 때마다 평가되므로 결과가 달라질 수 있음
- 배열 리터럴에서 콤마 사이의 값을 생략하면 정의되지 않은 요소가 들어감
- 배열 리터럴 내부의 마지막 표현식 다음에 콤마가 단 하나 있으면 정의되지 요소가 만들어지지는 않으나, 그 마지막 표현식 다음의 인덱스로 배열에 접근하려는 표현식은 undefined
[ ] // 빈 배열 [1+2, 3+4] // 요소가 두개인 배열 // 배열 초기화 표현식 내부의 요소 표현식 // 이 표현식은 중첩된 배열 반환함 let matrix = [[1,2,3], [4,5,6], [7,8,9]]; // 다음 요소 다섯개 중에 세 개는 정의되지 않음 let sparseArray = [1,,,,5];
- 객체 초기화 표현식
- 배열 초기화 표현식과는 달리 중괄호를 사용하고, 각 하위 표현식은 프로퍼티 이름과 콜론(:)으로 시작
- ES6 이후에는 객체 리터럴 문법의 기능이 풍부해짐 ⇒ 중첩 가능해짐
let p = { x: 2.3, y: -1.2 }; let q = {}; // 중첩 가능 let rectangle = { upperLeft: { x: 2, y: 2 }, lowerRight: { x: 4, y: 5 } }
📍 함수 정의 표현식
- 함수를 정의하며, 그 값이 함수
- ‘함수 리터럴’이라고도 부름
- function 키워드로 시작하고 괄호 안에 0개 이상의 식별자(매개변수 이름)을 쓴 뒤, 중괄호 안에 자바스크립트 코드(함수 바디)를 쓰는 형태
- 함수 정의 표현식에 함수 이름을 쓸 수도 있음
- ES6 이후에는 함수 표현식을 간결한 ‘화살표 함수’문법으로 쓸 수 있음
let square = function(x) { return x*x; };
📍 프로퍼티 접근 표현식
- 객체 프로퍼티나 배열 요소의 값으로 평가됨
- 자바스크립트에는 2가지 프로퍼티 접근 문법이 있음 (마침표 사용, 대괄호 사용)
- 해당되는 이름의 프로퍼티가 존재하지 않는다면 프로퍼티 접근 표현식의 값은 undefined
- 어떤 스타일의 프로퍼티 접근 표현식을 쓰든 .이나 [ 앞에 있는 표현식을 첫 번째로 평가 ⇒ 그 값이 null이나 undefined이면 이 둘은 프로퍼티를 가질 수 없는 값이므로 표현식은 TypeError 발생시킴
- .식별자 문법 : 더 간결하지만, 접근하고자 하는 이름이 유효한 식별자이고 그 이름을 알고 있을 때만 사용 가능
- 대괄호 표기법 : 프로퍼티 이름에 스페이스나 구두점이 들어 있거나, 숫자인 경우(배열), 프로퍼티 이름이 고정되어 있지 않고 계산 결과일 때 사용해야 함
// 2가지 프로퍼티 접근 문법
expression.identifier // 마침표 사용 (expression: 객체, identifier: 원하는 프로퍼티 이름)
expressiont[expression] // 대괄호 사용 (대괄호 안의 expression: 프로퍼티 이름/배열 요소 인덱스)
// 예제
let o = { x: 1, y: { z: 3 }}; // 예제 객체
let a = [o, 4, [5, 6]]; // 객체를 담고 있는 예제 배열
o.x // 표현식 o의 프로퍼티 x
o["x"] // 표현식 o의 프로퍼티 x
o.y.z // 표현식 o.y의 프로퍼티 z
a[1] // 표현식 a의 인덱스 1에 있는 요소
a[2]["1"] // 표현식 a[2]의 인덱스 1에 있는 요소
- 조건부 프로퍼티 접근
- ES2020에서 추가된 새로운 프로퍼티 접근 표현식
- ?.과 ?.[] 문법을 사용해 TypeError 방지 가능(왼쪽 표현식이 null / undefined일 때 일어나는 TypeError)
- ?.와 ?.[] 문법을 사용한 프로퍼티 접근은 ‘단축 평가’ ⇒ ?.의 왼쪽에 있는 하위 표현식이 null/undefined로 평가되면 더 이상 프로퍼티에 접근하려 하지 않고 전체 표현식을 즉시 undefined로 평가
expression ?. identifier // expression이 null/undefined이면 프로퍼티 identifier에 접근하려는 시도 없이 undefined로 평가 expression ?.[expression] // 예제 let a = { b: null }; a.b?.c.d // => undefined (a.b는 유효한 프로퍼티 접근 표현식이지만 값이 null이므로 즉시 undefined로 평가)
let a; // 변수 초기화 안함 let index = 0; try { a[index++]; // TypeError 발생 } catch(e) { index // => 1: index는 TypeError 발생하기 전에 증가함 } a?.[index++] // => undefined index // => 1: ?.[]는 단축 평가이므로 index가 증가하지 않음 a[index++] // TypeError 발생
📍 호출 표현식
- 함수나 메서드를 호출(실행)하는 문법
- 호출할 함수로 평가되는 함수 표현식으로 시작하며, 그 다음에 여는 괄호를 쓰고, 콤마로 구분된 0개 이상의 함수 인자 표현식 리스트를 쓰고, 닫는 괄호로 끝남
- 첫 번째로 함수 표현식을 평가, 그 다음으로 함수 인자 표현식을 평가해 인자 값 리스트 만듦
- 호출 표현식 맨 앞에 있는 표현식이 프로퍼티 접근 표현식이라면, 이 호출은 메서드 호출이라고도 함
f(0) // f는 함수 표현식, 0은 인자 표현식
Math.max(x,y,z) // Math.max는 함수, x, y, z는 인자
a.sort() // a.sort는 함수, 인자는 없음
🔅 조건부 호출
- ES2020에서는 () 대신 ?.()를 통해 함수 호출 가능
- ?.() 호출 문법을 사용하면 ?. 왼쪽의 표현식이 null/undefined로 평가될 때 호출 표현식 전체를 undefined로 평가하고, 예외는 일어나지 않음
- ES2019 이전에는 sort() 와 같이 선택 사항인 함수 인자를 받는 메서드 작성 시 if문을 통해 인자가 전달됐는지 확인해야 했으나 ES2020의 조건부 호출 문법을 쓰면 ?.()를 통해 함수를 호출하기만 하면 됨
- ?.()는 왼쪽에 있는 것이 null/undefined인지만 체크하며, 값이 실제로 함수인지까지 체크하지는 않음
- ?.()를 사용한 함수 호출 역시 단축 평가임 ⇒ ?. 왼쪽의 값이 null/undefined이면 괄호 안에 있는 함수 인자 표현식은 평가되지 않음
- 메서드 호출에는 반드시 프로퍼티 접근이 수반됨
function square(x, log) { // 두 번째 인자는 선택 사항인 함수
log?.(x); // 함수를 받았으면 호출
return x*x;
}
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?.() // 일반적인 프로퍼티 접근, 조건부 호출
📍 객체 생성 표현식
- 객체를 생성하고 함수(생성자)를 호출해 객체 프로퍼티를 초기화함
- 호출 표현식과 같지만, 앞에 new 키워드를 붙인다는 점이 다름
- 생성자 함수에 전달할 인자가 없다면 빈 괄호 생략 가능
- 객체 생성 표현식의 값은 새로 생성된 객체
new Object()
new Point(2, 3)
// 전달할 인자 없다면 빈 괄호 생략 가능
new Object
new Date
📍 연산자 개요
- 자바스크립트 연산자는 필요에 따라 피연산자의 타입을 변환함
- EX) “3” * “5”의 결과는 숫자 15 (자바스크립트가 피연산자를 숫자로 변환하므로)
- 자바스크립트 값은 모두 true나 false 같은 값이므로 불 타입의 피연산자를 예상하는 연산자는 어떤 타입의 피연산자라도 받을 수 있음
- 일부 표현식에는 이후의 평과 결과에 영향을 미치는 부수 효과가 있음
- EX) 할당 연산자, 증감 연산자, delete 연산자
- 함수나 생성자 바디에 부수 효과가 있는 연산자를 사용하면 해당 함수 호출이나 객체 생성 표현식에도 부수 효과가 있음
- 어떠한 연산자보다도 프로퍼티 접근과 호출 표현식, 배열 인덱스의 우선순위가 더 높음
- ?? 연산자는 ||나 && 사이의 우선순위는 아직 정의되지 않았으며, ES2020은 ??를 ||나 &&와 함께 사용할 때 명시적으로 괄호를 사용할 것을 요구함
- ?? 연산자: 첫 번째로 정의된 값을 반환
a ?? b // a가 null과 undefined가 아니면 결과는 a, 그 외에는 b
// 예시
let firstName = null;
let lastName = null;
let nickName = "바이올렛";
// null이나 undefined가 아닌 첫 번째 피연산자
alert(firstName ?? lastName ?? nickName ?? "익명의 사용자"); // 바이올렛
- **(지수), *(곱셈), /(나눗셈), %(나눗셈), -(뺄셈), 이 다섯 기본 연산자는 피연산자를 평가해서 필요하다면 숫자로 변환 후 연산을 진행함 (숫자가 아니며 숫자로 변환 불가능한 피연산자는 NaN 값으로 변환됨)
- ** 연산자(Math.pow()와 동일)
- 다른 연산자들과 달리 오른쪽에서 왼쪽으로 동작
2**2**3 // (2**(2**3))
- / 연산(나눗셈)
- 결과는 항상 부동 소수점
- 0으로 나누면 양의 무한대 또는 음의 무한대
- 0을 0으로 나누면 결과는 NaN
- % 연산
- 결과의 부호는 첫 번째 피연산자를 따름
- 나머지 연산자는 일반적으로 정수 피연산자를 받지만, 부동 소수점 값도 가능
6.5 % 2.1 // => 0.2
- + 연산
- 두 피연산자의 타입이 일치하지 않으면 타입 변환 필요 (문자열 병합에 우선순위)
- == 연산자(동등 연산자)
- 값을 비교할 때 타입 변환을 허용함
- 두 피연산자가 ‘같다고 볼 수 있는지’ 체크
- 두 값의 타입이 달라도 값이 같으면 같은 값
- 하나가 null이고 다른 하나가 undefined이면 같은 값
"1" == true // => true : true를 숫자로 변환하고 문자열 1을 숫자 1로 변환 후 비교
- === 연산자(일치 연산자)
- 값을 비교할 때 타입 변환은 수행하지 않음
- 두 피연산자가 ‘완전히’ 일치하는지 체크
- 두 값이 다른 타입이면 같은 값이 아님
- 두 값이 모두 null이거나 모두 undefined이면 같은 값
- 두 값 중 하나라도 NaN이면 같은 값이 아님
🔅 NaN은 자기 자신을 포함해 어떤 값과도 같지 않음
- in 연산자
- 왼쪽 피연산자가 문자열, 심벌, 문자열로 변환될 수 있는 값이라고 예상하며, 오른쪽 피연산자는 객체로 예상함
- 왼쪽 피연산자가 오른쪽 객체의 프로퍼티 이름일 경우 true를 반환함
let point = { x: 1, y: 2 }; "x" in point // => true "z" in point // => false : 객체에는 "z" 프로터피가 없음 "toString" in point // => true : 객체는 toString 메소드를 상속함
let data = [1, 2, 3]; "0" in data // => true : 배열에 요소(인덱스) "0"이 있음 1 in data // => true : 숫자는 문자열로 변환되며 요소(인덱스) "1"이 있음
- instanceof 연산자
- 왼쪽 피연산자는 객체, 오른쪽 피연산자는 객체의 클래스라고 예상함
- 왼쪽의 객체가 오른쪽 클래스의 인스턴스면 true를 반환함
- 오른쪽 피연산자가 객체의 클래스가 아니면 TypeError 발생
let d = new Date(); d instanceof Date; // => true d instanceof Object; // => true : 객체는 모두 Object의 인스턴스임
- && 연산자
- 왼쪽의 값이 false 같은 값이면 전체 표현식의 값도 반드시 false 같은 값이므로 오른쪽의 표현식은 평가하지도 않음 ⇒ 단축 평가(short circuit)
if(a === b) stop(); // a === b일 때만 stop() 호출
(a === b) && stop(); // 위와 똑같이 동작
'FrontEnd > Javascript' 카테고리의 다른 글
[모던 자바스크립트 Deep Dive🦎] 7장 : 연산자 (0) | 2023.03.29 |
---|---|
[모던 자바스크립트 Deep Dive🦎] 6장 : 데이터 타입 (0) | 2023.03.24 |
[모던 자바스크립트 Deep Dive🦎] 5장 : 표현식과 문 (0) | 2023.03.22 |
[모던 자바스크립트 Deep Dive🦎] 4장 : 변수 (0) | 2023.03.20 |
[모던 자바스크립트 Deep Dive🦎] 1-3장 : 프로그래밍, 자바스크립트, 자바스크립트 개발 환경 (0) | 2023.03.20 |
Comments