회고록 블로그

[공부 필기] JavaScript 문법 공부 22일차 본문

2. 프로그래밍 언어 공부/JavaScript

[공부 필기] JavaScript 문법 공부 22일차

김간장 2022. 5. 18. 22:26

※ 필자는 초초초보자입니다.

※ 틀린 내용에 대한 피드백은 언제든지 환영합니다.

 

 

공부하고 있는 자료 : modern JavaScript tutorial 

https://ko.javascript.info/optional-chaining

 

옵셔널 체이닝 '?.'

 

ko.javascript.info

 

► 스펙에 추가된지 얼마 안 된 따끈따끈한 문법(?)

 

✅ 옵션널 체이닝?

- 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);

 

 

 

Comments