[공부 필기] JavaScript 문법 공부 22일차
※ 필자는 초초초보자입니다.
※ 틀린 내용에 대한 피드백은 언제든지 환영합니다.
공부하고 있는 자료 : modern JavaScript tutorial
https://ko.javascript.info/optional-chaining
► 스펙에 추가된지 얼마 안 된 따끈따끈한 문법(?)
✅ 옵션널 체이닝?
- optional chaining
- 사용방법: ?.
- 프로퍼티가 없는 중첩 객체를 에러 없이 안전하게 접근할 수 있다!
💡 중첩 객체 예시
let user1 = {
name: "soy",
age: 1,
address: {
country: "KOR",
city: "seoul",
"street address": "123-45",
},
};
✅ 필요한 이유
- 아래의 코드는 에러가 발생한다.
► street address가 없기 때문
"use strict";
let user = {
name: "mango",
age: 2,
};
function showStreetAddress(obj) {
console.log(obj["address"]["street address"]);
}
showStreetAddress(user); // Uncaught TypeError: Cannot read properties of undefined (reading 'street address')
💡 참고로, address라는 객체가 일단 생성이 되어있을 땐 에러가 발생하지 않았다.
"use strict";
let user = {
name: "mango",
age: 2,
address: {}, // 빈 객체
};
function showStreetAddress(obj) {
console.log(obj["address"]["street address"]);
}
showStreetAddress(user); // undefined
- 자바스크립트를 사용해서 페이지에 존재하지 않는 요소에 접근 후 요소의 정보를 가져오려고 하면 문제가 발생한다고..한다.
► querySelector의 호출 결과가 null이면 에러가 발생한다.
► 참고📌 querySelector는 html의 엘리먼트(요소)를 가져올 때 사용하며, innerHTML은 해당 엘리먼트의 내용을 가져온다.
예를 들어 HTML 문서에 <div class="my-element">Hello World!</div> 가 있으면
아래의 코드는 Hello World!가 html 변수에 저장된다.
"use strict";
let html = document.querySelector('.my-element').innerHTML;
// 코드 출처 : 모던 자바스크립트 (https://ko.javascript.info/optional-chaining)
- 위의 에러들이 발생하지 않도록 처리할 때는 && 연산자를 사용하곤 했는데
[옵셔널 체이닝]이 등장하면서 ?. 으로 처리할 수 있게 됐다.
► 이전의 방법
: 코드가 아주 길어진다는 단점이 있다.
"use strict";
let user = {
name: "mango",
age: 2,
};
function showStreetAddress(obj) {
console.log(obj && obj["address"] && obj["address"]["street address"]); // &&로 계속 묶음
}
showStreetAddress(user); // 결과 : undefined
► 옵셔널 체이닝
: ?. 앞의 평가 대상이 undefined나 null 이면 평가를 멈추고 undefined를 반환한다.
...
function showStreetAddress(obj) {
console.log(obj?.address?.["street address"]);
}
showStreetAddress(user); // undefined
✅ 주의사항
- ?.의 앞 평가 대상에만 동작한다.
- 예를 들어서 아래와 같은 코드가 있다고 가정하자.
► user라는 객체 안에 address라는 객체가 있고, 그 프로퍼티 중 하나로 "street address"가 있는 상황
- 이때 다음과 같은 결과가 출력된다.
► user(객체)가 null일 때
let user = null;
console.log(user?.address["street address"]); // undefined
» ?. 앞에 있는 user가 평가 대상이 되며, user가 null이거나 undefined이기 때문에 undefined가 출력된다.
► user(객체)가 존재하지만 address라는 객체는 없을 때
let user = {
name: "mango",
age: 2,
};
console.log(user?.address["street address"]); // Error!
» ?. 앞에 있는 user는 존재하므로(undefined나 null이 아니기 때문에) 넘어간다.
하지만 뒤에 나오는 address 객체는 옵셔널 체이닝을 사용하지 않았기 때문에
address 안에 프로퍼티 "street address"를 찾지 못하고 에러가 발생한다.
» ?. 앞에 있는 평가 대상만 평가한다는 것을 유의해야한다.
► 변수 자체가 선언되지 않았을 때
console.log(user?.address);
» user라는 변수 자체가 선언되지 않았을 때 ReferenceError가 발생한다.
- 옵셔널 체이닝은 [남용]하면 안된다.
► 존재하지 않아도 괜찮은 대상에만 사용해야한다.
► 위의 예시처럼 user 객체는 반드시 존재해야하되 address 객체는 필수값이 아닐 때 사용하는 것이 바람직하다고 한다.
► 잘못 사용하면 필수값인 user에 값이 할당됐는지 바로 알아채지 못해서 실수를 찾기 힘들고 디버깅이 어려워진다.
✅ 단락 평가
- ?.의 동작원리가 단락 평가이다.
► user?.address 코드에서
user라는 평가 대상에 값이 없으면(=undefined, null) 즉시 평가를 멈춘다.
- 이처럼 왼쪽 평가대상에 값이 없으면 즉시 평가를 멈추는 것을 [단락 평가(short-circuit)]라고 한다.
✅ ?.()
- ?.은 연산자가 아닌 특별한 문법 구조체이다.
- 이 문법 구조체는 이런 것도 사용할 수 있다.
- 에러 없이 메서드가 존재하는지 확인하고 실행을 하려면
다음과 같이 ?.() 를 사용하면 된다.
"use strict";
let user = {
name: "mango",
age: 2,
};
user?.showAge?.(); // 아무것도 출력되지도 실행되지도 않음
► 여기에서 showAge는 메서드이다.
► user라는 객체는 존재하기 때문에 첫번째 ?. 평가는 무사히 성공하고 user 객체에 접근한다.
그 다음에 showAge라는 메서드가 존재하는지 평가하는데, 존재하지 않기 때문에(=undefined나 null) 즉시 평가가 멈춘다.
그것도 에러없이!
- 만약 ?.() 를 사용하지 않으면 TypeError가 발생한다.
"use strict";
let user = {
name: "mango",
age: 2,
};
user?.showAge(); //Uncaught TypeError: user?.showAge is not a function
✅ ?.[]
- ?.[]은 객체의 프로퍼티에 접근할 때 사용할 수 있는 방법 중 하나이다.
- 객체의 프로퍼티 존재 여부가 확실치 않은 경우에 안전하게 프로퍼티를 읽을 수 있다.
"use strict";
let user = {
name: "mango",
age: 2,
};
console.log(user.address.city); // TypeError
console.log(user.address['city']); // TypeError
console.log(user["address"]["city"]); // TypeError
console.log(user.address?.["city"]); // undefined
console.log(user["address"]?.['city']); // undefined
- 참고📌 위에서 옵셔널 체이닝의 예시 코드를 작성할 때, 프로퍼티 키(프로퍼티 이름)가 두 문자로 구성되어 있어서 대괄호를 사용했다.
✅ 활용 예시
- ?.와 delete를 함께 사용할 수 있다.
delete user?.address; // user가 존재하면 user.address를 삭제한다.
► user.address가 존재하지 않아도 에러가 발생하지 않는다.
- 삭제할 때(delete)는 사용할 수 있지만 쓰기에는 사용할 수 없다.
► 에러가 발생하는 이유는 왼쪽의 식이 undefined가 되기 때문이라고 한다.
이 때문에 undefined = {}; 가 된다.
"use strict";
let user = {
name: "mango",
age: 2,
};
user?.address = {}; // Uncaught SyntaxError: Invalid left-hand side in assignment
console.log(user);