์ต์ ๋ ์ฒด์ด๋(?.)๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์(??)๋ก ๋ ์์ ํ๊ณ , ๊นจ๋ํ๋ฉฐ, ํ๋ ฅ์ ์ธ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ์์ฑํ์ธ์. ์ผ๋ฐ์ ์ธ ๋ฐํ์ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ๊ณ ๋๋ฝ๋ ๋ฐ์ดํฐ๋ฅผ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํฉ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ์ต์ ๋ ์ฒด์ด๋๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์: ๊ฒฌ๊ณ ํ๊ณ ํ๋ ฅ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถํ๊ธฐ
์น ๊ฐ๋ฐ์ ์ญ๋์ ์ธ ์ธ๊ณ์์ ์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์
์ REST API๋ถํฐ ์ฌ์ฉ์ ์
๋ ฅ, ์๋ํํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ด๋ฅด๊ธฐ๊น์ง ๋ค์ํ ๋ฐ์ดํฐ ์์ค์ ์ํธ์์ฉํฉ๋๋ค. ์ด๋ฌํ ์ ๋ณด์ ์ง์์ ์ธ ํ๋ฆ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๊ฐ ํญ์ ์์ธก ๊ฐ๋ฅํ๊ฑฐ๋ ์์ ํ์ง ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๊ฐ๋ฐ์๋ค์ด ๊ฐ์ฅ ํํ๊ฒ ๊ฒช๋ ๊ณจ์นซ๊ฑฐ๋ฆฌ ์ค ํ๋๋ null ๋๋ undefined์ผ ์ ์๋ ๊ฐ์ฒด์ ์์ฑ์ ์ ๊ทผํ๋ ค๋ค ๋์ฐํ "TypeError: Cannot read properties of undefined (reading 'x')" ์ค๋ฅ๋ฅผ ๋ง๋๋ ๊ฒ์
๋๋ค. ์ด ์ค๋ฅ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ์ค๋จ์ํค๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ฐฉํดํ๋ฉฐ, ๋ฐฉ์ด์ ์ธ ํ์ธ ์ฝ๋๋ก ์ฝ๋๋ฅผ ์ด์ง๋ฝ๊ฒ ๋ง๋ญ๋๋ค.
๋คํํ๋, ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ ์ด๋ฌํ ๋ฌธ์ ๋ค์ ํด๊ฒฐํ๊ธฐ ์ํด ํน๋ณํ ์ค๊ณ๋ ๋ ๊ฐ์ง ๊ฐ๋ ฅํ ์ฐ์ฐ์ โ ์ต์
๋ ์ฒด์ด๋(?.)๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์(??) โ ๋ฅผ ๋์
ํ์ต๋๋ค. ES2020์์ ํ์คํ๋ ์ด ๊ธฐ๋ฅ๋ค์ ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ค์ด ์ ์ฌ์ ์ผ๋ก ๋๋ฝ๋ ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋ ๋ ๊นจ๋ํ๊ณ , ๋ ํ๋ ฅ์ ์ด๋ฉฐ, ๊ฒฌ๊ณ ํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๊ฒ ํด์ค๋๋ค. ์ด ์ข
ํฉ ๊ฐ์ด๋์์๋ ๊ฐ ์ฐ์ฐ์๋ฅผ ๊น์ด ํ๊ณ ๋ค์ด ๊ทธ ๊ธฐ๋ฅ, ์ด์ , ๊ณ ๊ธ ์ฌ์ฉ ์ฌ๋ก, ๊ทธ๋ฆฌ๊ณ ์ด๋ค์ด ์ด๋ป๊ฒ ์๋์ง ํจ๊ณผ๋ฅผ ๋ด์ด ๋ ์์ธก ๊ฐ๋ฅํ๊ณ ์ค๋ฅ ์๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ง๋๋์ง ํ๊ตฌํ ๊ฒ์
๋๋ค.
๋ณต์กํ ์ํฐํ๋ผ์ด์ฆ ์๋ฃจ์ ์ ๊ตฌ์ถํ๋ ์๋ จ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์์ด๋ , ์ด์ ๋ง ์ฌ์ ์ ์์ํ๋ ๊ฐ๋ฐ์์ด๋ , ์ต์ ๋ ์ฒด์ด๋๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์๋ฅผ ๋ง์คํฐํ๋ ๊ฒ์ ์ฌ๋ฌ๋ถ์ ์ฝ๋ฉ ์ค๋ ฅ์ ํฌ๊ฒ ํฅ์์ํค๊ณ ์ค์ ๋ฐ์ดํฐ์ ๋ถํ์ค์ฑ์ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ๋์์ด ๋ ๊ฒ์ ๋๋ค.
๋ฌธ์ : ์ ์ฌ์ ์ผ๋ก ๋๋ฝ๋ ๋ฐ์ดํฐ ํ์ํ๊ธฐ
์ต์ ๋ ์ฒด์ด๋๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์๊ฐ ๋ฑ์ฅํ๊ธฐ ์ , ๊ฐ๋ฐ์๋ค์ ์ค์ฒฉ๋ ์์ฑ์ ์์ ํ๊ฒ ์ ๊ทผํ๊ธฐ ์ํด ์ฅํฉํ๊ณ ๋ฐ๋ณต์ ์ธ ์กฐ๊ฑด๋ถ ํ์ธ์ ์์กดํด์ผ ํ์ต๋๋ค. ํํ ์๋๋ฆฌ์ค๋ฅผ ์๊ฐํด ๋ด ์๋ค: API๋ก๋ถํฐ ๋ฐ์ ์ฌ์ฉ์ ๊ฐ์ฒด์ ํญ์ ์กด์ฌํ์ง๋ ์์ ์ ์๋ ์ฌ์ฉ์์ ์ฃผ์ ์ธ๋ถ ์ ๋ณด์ ์ ๊ทผํ๋ ๊ฒฝ์ฐ์ ๋๋ค.
์ ํต์ ์ธ ์ ๊ทผ ๋ฐฉ์๊ณผ ๊ทธ ํ๊ณ
1. ๋
ผ๋ฆฌ AND (&&) ์ฐ์ฐ์ ์ฌ์ฉ
์ด๊ฒ์ ์์ฑ ์ ๊ทผ์ ๋จ์ถ ํ๊ฐ(short-circuiting)ํ๋ ๋ฐ ๋๋ฆฌ ์ฌ์ฉ๋ ๊ธฐ์ ์ด์์ต๋๋ค. ์ฒด์ธ์ ์ด๋ ๋ถ๋ถ์ด๋ falsy ๊ฐ์ด๋ฉด, ํํ์์ ์ค๋จ๋๊ณ ๊ทธ falsy ๊ฐ์ ๋ฐํํฉ๋๋ค.
const user = {
id: 'u123',
name: 'Alice Smith',
contact: {
email: 'alice@example.com',
phone: '123-456-7890'
}
// address is missing
};
// Attempt to get the street from user.address
const street = user && user.contact && user.contact.address && user.contact.address.street;
console.log(street); // undefined
const userWithAddress = {
id: 'u124',
name: 'Bob Johnson',
contact: {
email: 'bob@example.com'
},
address: {
street: '123 Main St',
city: 'Metropolis',
country: 'USA'
}
};
const city = userWithAddress && userWithAddress.address && userWithAddress.address.city;
console.log(city); // 'Metropolis'
// What if `user` itself is null or undefined?
const nullUser = null;
const streetFromNullUser = nullUser && nullUser.address && nullUser.address.street;
console.log(streetFromNullUser); // null (safe, but verbose)
์ด ์ ๊ทผ ๋ฐฉ์์ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ์ง๋ง, ๋ค์๊ณผ ๊ฐ์ ๋จ์ ์ด ์์ต๋๋ค:
- ์ฅํฉํจ: ์ค์ฒฉ์ ๊ฐ ๋จ๊ณ๋ง๋ค ๋ฐ๋ณต์ ์ธ ํ์ธ์ด ํ์ํฉ๋๋ค.
- ์ค๋ณต์ฑ: ๋ณ์ ์ด๋ฆ์ด ์ฌ๋ฌ ๋ฒ ๋ฐ๋ณต๋ฉ๋๋ค.
- ์ ์ฌ์ ์ธ ์คํด ์์ง: ์ฒด์ธ์์
0,'',false์ ๊ฐ์ falsy ๊ฐ์ ๋ง๋๋ฉด ์ด๋ฅผ ๋ฐํํ ์ ์๋๋ฐ, ์ด๋ ํน๋ณํnull์ด๋undefined๋ฅผ ํ์ธํ๋ ค๋ ์๋์ ๋ค๋ฅผ ์ ์์ต๋๋ค.
2. ์ค์ฒฉ๋ If-๋ฌธ
๋ ๋ค๋ฅธ ์ผ๋ฐ์ ์ธ ํจํด์ ๊ฐ ๋จ๊ณ์์ ์กด์ฌ ์ฌ๋ถ๋ฅผ ๋ช ์์ ์ผ๋ก ํ์ธํ๋ ๊ฒ์ด์์ต๋๋ค.
let country = 'Unknown';
if (userWithAddress) {
if (userWithAddress.address) {
if (userWithAddress.address.country) {
country = userWithAddress.address.country;
}
}
}
console.log(country); // 'USA'
// With the user object missing address:
const anotherUser = {
id: 'u125',
name: 'Charlie Brown'
};
let postcode = 'N/A';
if (anotherUser && anotherUser.address && anotherUser.address.postcode) {
postcode = anotherUser.address.postcode;
}
console.log(postcode); // 'N/A'
์ด ์ ๊ทผ ๋ฐฉ์์ ๋ช ์์ ์ด๊ธด ํ์ง๋ง, ํํ "์ฝ๋ฐฑ ์ง์ฅ" ๋๋ "๋ฉธ๋ง์ ํผ๋ผ๋ฏธ๋"๋ก ์๋ ค์ง, ๊น๊ฒ ๋ค์ฌ์ฐ๊ธฐ ๋๊ณ ์ฝ๊ธฐ ์ด๋ ค์ด ์ฝ๋๋ก ์ด์ด์ง๋๋ค. ๋ ๋ณต์กํ ๋ฐ์ดํฐ ๊ตฌ์กฐ์์๋ ํ์ฅ์ฑ์ด ๋จ์ด์ง๋๋ค.
์ด๋ฌํ ์ ํต์ ์ธ ๋ฐฉ๋ฒ๋ค์ ์ ์ฌ์ ์ผ๋ก ๋๋ฝ๋ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ํ์ํ๊ธฐ ์ํ ๋ ์ฐ์ํ๊ณ ๊ฐ๊ฒฐํ ํด๊ฒฐ์ฑ ์ ํ์์ฑ์ ๊ฐ์กฐํฉ๋๋ค. ๋ฐ๋ก ์ด ์ง์ ์์ ์ต์ ๋ ์ฒด์ด๋์ด ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์ ๊ฒ์ ์ฒด์ธ์ ๋ก ๋ฑ์ฅํฉ๋๋ค.
์ต์
๋ ์ฒด์ด๋(?.) ์๊ฐ: ๋น์ ์ ์์ ํ ํ์๊ธฐ
์ต์
๋ ์ฒด์ด๋์ ์๋ฐ์คํฌ๋ฆฝํธ์ ์ถ๊ฐ๋ ํ์์ ์ธ ๊ธฐ๋ฅ์ผ๋ก, ์ฒด์ธ ๋ด์ ๊ฐ ์ฐธ์กฐ๊ฐ ์ ํจํ์ง ๋ช
์์ ์ผ๋ก ๊ฒ์ฆํ ํ์ ์์ด ์ฐ๊ฒฐ๋ ๊ฐ์ฒด ์ฒด์ธ ๊น์์ด ์์นํ ์์ฑ์ ๊ฐ์ ์ฝ์ ์ ์๊ฒ ํด์ค๋๋ค. ?. ์ฐ์ฐ์๋ . ์ฒด์ด๋ ์ฐ์ฐ์์ ์ ์ฌํ๊ฒ ์๋ํ์ง๋ง, ์ฐธ์กฐ๊ฐ null ๋๋ undefined์ผ ๊ฒฝ์ฐ ์ค๋ฅ๋ฅผ ๋์ง๋ ๋์ "๋จ์ถ ํ๊ฐ"๋์ด undefined๋ฅผ ๋ฐํํฉ๋๋ค.
์ต์ ๋ ์ฒด์ด๋์ ์๋ ๋ฐฉ์
obj?.prop์ ๊ฐ์ ํํ์์์ ์ต์
๋ ์ฒด์ด๋ ์ฐ์ฐ์(?.)๋ฅผ ์ฌ์ฉํ๋ฉด, ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ๋จผ์ obj๋ฅผ ํ๊ฐํฉ๋๋ค. ๋ง์ฝ obj๊ฐ null๋ ์๋๊ณ undefined๋ ์๋๋ฉด, prop์ ์ ๊ทผ์ ๊ณ์ํฉ๋๋ค. ๋ง์ฝ obj๊ฐ null์ด๊ฑฐ๋ undefined์ด๋ฉด, ์ ์ฒด ํํ์์ ์ฆ์ undefined๋ก ํ๊ฐ๋๊ณ ์ค๋ฅ๋ ๋ฐ์ํ์ง ์์ต๋๋ค.
์ด ๋์์ ์ฌ๋ฌ ๋จ๊ณ์ ์ค์ฒฉ์ ๊ฑธ์ณ ํ์ฅ๋๋ฉฐ ์์ฑ, ๋ฉ์๋, ๋ฐฐ์ด ์์์ ๋ชจ๋ ์๋ํฉ๋๋ค.
๊ตฌ๋ฌธ ๋ฐ ์ค์ ์์
1. ์ ํ์ ์์ฑ ์ ๊ทผ
์ด๊ฒ์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๋ก, ์ค์ฒฉ๋ ๊ฐ์ฒด ์์ฑ์ ์์ ํ๊ฒ ์ ๊ทผํ ์ ์๊ฒ ํด์ค๋๋ค.
const userProfile = {
id: 'p001',
name: 'Maria Rodriguez',
location: {
city: 'Barcelona',
country: 'Spain'
},
preferences: null // preferences object is null
};
const companyData = {
name: 'Global Corp',
address: {
street: '456 Tech Ave',
city: 'Singapore',
postalCode: '123456'
},
contactInfo: undefined // contactInfo is undefined
};
// Accessing nested properties safely
console.log(userProfile?.location?.city); // 'Barcelona'
console.log(userProfile?.preferences?.theme); // undefined (because preferences is null)
console.log(companyData?.contactInfo?.email); // undefined (because contactInfo is undefined)
console.log(userProfile?.nonExistentProperty?.anotherOne); // undefined
// Without optional chaining, these would throw errors:
// console.log(userProfile.preferences.theme); // TypeError: Cannot read properties of null (reading 'theme')
// console.log(companyData.contactInfo.email); // TypeError: Cannot read properties of undefined (reading 'email')
2. ์ ํ์ ๋ฉ์๋ ํธ์ถ
๊ฐ์ฒด์ ์กด์ฌํ์ง ์์ ์ ์๋ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋๋ ์ต์
๋ ์ฒด์ด๋์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ง์ฝ ๋ฉ์๋๊ฐ null์ด๊ฑฐ๋ undefined์ด๋ฉด, ํํ์์ undefined๋ก ํ๊ฐ๋๊ณ ๋ฉ์๋๋ ํธ์ถ๋์ง ์์ต๋๋ค.
const analyticsService = {
trackEvent: (name, data) => console.log(`Tracking event: ${name} with data:`, data)
};
const userService = {}; // No 'log' method here
analyzerService.trackEvent?.('user_login', { userId: 'u123' });
// Expected output: Tracking event: user_login with data: { userId: 'u123' }
userService.log?.('User updated', { id: 'u124' });
// Expected output: Nothing happens, no error thrown. The expression returns undefined.
์ด๋ ์ ํ์ ์ฝ๋ฐฑ, ํ๋ฌ๊ทธ์ธ, ๋๋ ํจ์๊ฐ ์กฐ๊ฑด๋ถ๋ก ์กด์ฌํ ์ ์๋ ๊ธฐ๋ฅ ํ๋๊ทธ๋ฅผ ๋ค๋ฃฐ ๋ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
3. ์ ํ์ ๋ฐฐ์ด/๋๊ดํธ ํ๊ธฐ๋ฒ ์ ๊ทผ
์ต์ ๋ ์ฒด์ด๋์ ๋ฐฐ์ด์ ์์๋ ํน์ ๋ฌธ์๊ฐ ํฌํจ๋ ์์ฑ์ ์ ๊ทผํ๊ธฐ ์ํด ๋๊ดํธ ํ๊ธฐ๋ฒ๊ณผ๋ ํจ๊ป ์๋ํฉ๋๋ค.
const userActivities = {
events: ['login', 'logout', 'view_profile'],
purchases: []
};
const globalSettings = {
'app-name': 'My App',
'version-info': {
'latest-build': '1.0.0'
}
};
console.log(userActivities?.events?.[0]); // 'login'
console.log(userActivities?.purchases?.[0]); // undefined (empty array, so element at index 0 is undefined)
console.log(userActivities?.preferences?.[0]); // undefined (preferences is not defined)
// Accessing properties with hyphens using bracket notation
console.log(globalSettings?.['app-name']); // 'My App'
console.log(globalSettings?.['version-info']?.['latest-build']); // '1.0.0'
console.log(globalSettings?.['config']?.['env']); // undefined
์ต์ ๋ ์ฒด์ด๋์ ์ฃผ์ ์ด์
-
๊ฐ๋
์ฑ ๋ฐ ๊ฐ๊ฒฐ์ฑ: ๋ฐฉ์ด์ ์ธ ํ์ธ์ ํ์ํ ์์ฉ๊ตฌ ์ฝ๋์ ์์ ๊ทน์ ์ผ๋ก ์ค์ฌ์ค๋๋ค. ์ฝ๋๊ฐ ํ๋์ ํจ์ฌ ๋ ๊นจ๋ํ๊ณ ์ดํดํ๊ธฐ ์ฌ์์ง๋๋ค.
// Before const regionCode = (user && user.address && user.address.country && user.address.country.region) ? user.address.country.region : 'N/A'; // After const regionCode = user?.address?.country?.region ?? 'N/A'; // (combining with nullish coalescing for default value) -
์ค๋ฅ ๋ฐฉ์ง:
null๋๋undefined์ ์์ฑ์ ์ ๊ทผํ๋ ค ํ ๋ ๋ฐ์ํ๋ ๋ฐํ์TypeError์ถฉ๋์ ์ ๊ฑฐํฉ๋๋ค. ์ด๋ ๋ ์์ ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ด์ด์ง๋๋ค. - ๊ฐ๋ฐ์ ๊ฒฝํ ํฅ์: ๊ฐ๋ฐ์๋ ๋ฐฉ์ด์ ์ธ ํ๋ก๊ทธ๋๋ฐ๋ณด๋ค ๋น์ฆ๋์ค ๋ก์ง์ ๋ ์ง์คํ ์ ์์ด ๊ฐ๋ฐ ์ฃผ๊ธฐ๊ฐ ๋นจ๋ผ์ง๊ณ ๋ฒ๊ทธ๊ฐ ์ค์ด๋ญ๋๋ค.
- ์ฐ์ํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ: ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฐ์ดํฐ๊ฐ ๋ถ๋ถ์ ์ผ๋ก๋ง ์ฌ์ฉ ๊ฐ๋ฅํ๊ฑฐ๋ ์์๊ณผ ๋ค๋ฅด๊ฒ ๊ตฌ์กฐํ๋ ์๋๋ฆฌ์ค๋ฅผ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ค๋๋ค. ์ด๋ ์ธ๋ถ API๋ ๋ค์ํ ๊ตญ์ ์์ค์์ ์์ฑ๋ ์ฌ์ฉ์ ์ฝํ ์ธ ๋ฅผ ๋ค๋ฃฐ ๋ ํํ ๋ฐ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์์ ์ฐ๋ฝ์ฒ ์ธ๋ถ ์ ๋ณด๋ ์ผ๋ถ ์ง์ญ์์๋ ์ ํ ์ฌํญ์ด์ง๋ง ๋ค๋ฅธ ์ง์ญ์์๋ ํ์์ผ ์ ์์ต๋๋ค.
์ต์ ๋ ์ฒด์ด๋์ ์ฌ์ฉํด์ผ ํ ๋์ ์ฌ์ฉํ์ง ๋ง์์ผ ํ ๋
์ต์ ๋ ์ฒด์ด๋์ ๋งค์ฐ ์ ์ฉํ์ง๋ง, ๊ทธ ์ ์ ํ ์ ์ฉ์ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค:
์ต์ ๋ ์ฒด์ด๋ ์ฌ์ฉ ์๊ธฐ:
-
์์ฑ์ด๋ ๋ฉ์๋๊ฐ ์ง์ ์ผ๋ก ์ ํ ์ฌํญ์ผ ๋: ์ด๋ ์ค๊ฐ ์ฐธ์กฐ๊ฐ
null๋๋undefined์ฌ๋ ๊ด์ฐฎ๊ณ , ์ ํ๋ฆฌ์ผ์ด์ ์ด ์๋ง๋ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํ์ฌ ๊ณ์ ์งํํ ์ ์์์ ์๋ฏธํฉ๋๋ค.const dashboardConfig = { theme: 'dark', modules: [ { name: 'Analytics', enabled: true }, { name: 'Reports', enabled: false } ] }; // If 'notifications' module is optional const notificationsEnabled = dashboardConfig.modules.find(m => m.name === 'Notifications')?.enabled; console.log(notificationsEnabled); // undefined if not found - ์ผ๊ด๋์ง ์์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง ์ ์๋ API ์๋ต์ ๋ค๋ฃฐ ๋: ๋ค๋ฅธ ์๋ํฌ์ธํธ๋ API ๋ฒ์ ์ ๋ฐ์ดํฐ๋ ๋๋๋ก ํน์ ํ๋๋ฅผ ์๋ตํ ์ ์์ต๋๋ค. ์ต์ ๋ ์ฒด์ด๋์ ์ด๋ฌํ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ์๋นํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
-
๋์ ์ผ๋ก ์์ฑ๋๊ฑฐ๋ ์ฌ์ฉ์๊ฐ ์ ๊ณตํ ๊ฐ์ฒด์ ์์ฑ์ ์ ๊ทผํ ๋: ๊ฐ์ฒด์ ํํ๋ฅผ ๋ณด์ฅํ ์ ์์ ๋
?.๋ ์์ ๋ง์ ์ ๊ณตํฉ๋๋ค.
์ต์ ๋ ์ฒด์ด๋ ์ฌ์ฉ์ ํผํด์ผ ํ ๋:
-
์์ฑ์ด๋ ๋ฉ์๋๊ฐ ์ค์ํ๊ณ *๋ฐ๋์* ์กด์ฌํด์ผ ํ ๋: ์์ฑ์ ๋ถ์ฌ๊ฐ ์ฌ๊ฐํ ๋ฒ๊ทธ๋ ์ ํจํ์ง ์์ ์ํ๋ฅผ ๋ํ๋ด๋ ๊ฒฝ์ฐ,
TypeError๊ฐ ๋ฐ์ํ๋๋ก ํ์ฌ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋ฅผ ๊ฐ์งํ๊ณ ์์ ํด์ผ ํฉ๋๋ค. ์ฌ๊ธฐ์?.๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฌธ์ ๊ฐ ๊ฐ๋ ค์ง ์ ์์ต๋๋ค.// If 'userId' is absolutely critical for every user object const user = { name: 'Jane' }; // Missing 'id' // A TypeError here would indicate a serious data integrity issue // console.log(user?.id); // Returns undefined, potentially masking an error // Prefer to let it error or explicitly check: if (!user.id) { throw new Error('User ID is missing and required!'); } -
๊ณผ๋ํ ์ฒด์ด๋์ผ๋ก ๋ช
ํ์ฑ์ด ๋จ์ด์ง ๋: ๊ฐ๊ฒฐํ์ง๋ง, ๋งค์ฐ ๊ธด ์ต์
๋ ์ฒด์ธ(์:
obj?.prop1?.prop2?.prop3?.prop4?.prop5)์ ์ฝ๊ธฐ ์ด๋ ค์์ง ์ ์์ต๋๋ค. ๋๋ก๋ ์ฝ๋๋ฅผ ๋๋๊ฑฐ๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ฌ๊ตฌ์ฑํ๋ ๊ฒ์ด ๋ ๋์ ์ ์์ต๋๋ค. -
null/undefined์ ๋ค๋ฅธ falsy ๊ฐ(0,'',false)์ ๊ตฌ๋ณํด์ผ ํ ๋: ์ต์ ๋ ์ฒด์ด๋์null๋๋undefined๋ง ํ์ธํฉ๋๋ค. ๋ค๋ฅธ falsy ๊ฐ์ ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํด์ผ ํ๋ ๊ฒฝ์ฐ, ๋ ๋ช ์์ ์ธ ํ์ธ์ด ํ์ํ๊ฑฐ๋ ๋ค์์ ๋ค๋ฃฐ ๋ ๋ณํฉ ์ฐ์ฐ์์ ๊ฒฐํฉํด์ผ ํ ์ ์์ต๋๋ค.
๋ ๋ณํฉ ์ฐ์ฐ์(??) ์ดํดํ๊ธฐ: ์ ํํ ๊ธฐ๋ณธ๊ฐ ์ค์
์ต์
๋ ์ฒด์ด๋์ด ์กด์ฌํ์ง *์์ ์๋ ์๋* ์์ฑ์ ์์ ํ๊ฒ ์ ๊ทผํ๋ ๋ฐ ๋์์ ์ค๋ค๋ฉด, ๋ ๋ณํฉ ์ฐ์ฐ์(??)๋ ๊ฐ์ด ๊ตฌ์ฒด์ ์ผ๋ก null ๋๋ undefined์ผ ๋ ๊ธฐ๋ณธ๊ฐ์ ์ ๊ณตํ๋ ๋ฐ ๋์์ ์ค๋๋ค. ์ข
์ข
์ต์
๋ ์ฒด์ด๋๊ณผ ํจ๊ป ์ฌ์ฉ๋์ง๋ง, ์ ํต์ ์ธ ๋
ผ๋ฆฌ OR(||) ์ฐ์ฐ์์๋ ๋ค๋ฅธ ๋์์ ํ๋ฉฐ ๋ค๋ฅธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค.
๋ ๋ณํฉ ์ฐ์ฐ์์ ์๋ ๋ฐฉ์
๋ ๋ณํฉ ์ฐ์ฐ์(??)๋ ์ผ์ชฝ ํผ์ฐ์ฐ์๊ฐ null ๋๋ undefined์ผ ๋ ์ค๋ฅธ์ชฝ ํผ์ฐ์ฐ์๋ฅผ ๋ฐํํ๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด ์ผ์ชฝ ํผ์ฐ์ฐ์๋ฅผ ๋ฐํํฉ๋๋ค. ์ด๋ 0, '', false์ ๊ฐ์ ๋ค๋ฅธ falsy ๊ฐ์ nullish๋ก ์ทจ๊ธํ์ง ์๊ธฐ ๋๋ฌธ์ ||์์ ์ค์ํ ์ฐจ์ด์ ์
๋๋ค.
๋
ผ๋ฆฌ OR (||)๊ณผ์ ์ฐจ์ด์
์ด๊ฒ์ ??๋ฅผ ์ดํดํ ๋ ํ์
ํด์ผ ํ ๊ฐ์ฅ ์ค์ํ ๊ฐ๋
์ผ ๊ฒ์
๋๋ค.
-
๋
ผ๋ฆฌ OR (
||): ์ผ์ชฝ ํผ์ฐ์ฐ์๊ฐ ์ด๋ค falsy ๊ฐ์ด๋ (false,0,'',null,undefined,NaN) ์ค๋ฅธ์ชฝ ํผ์ฐ์ฐ์๋ฅผ ๋ฐํํฉ๋๋ค. -
๋ ๋ณํฉ ์ฐ์ฐ์(
??): ์ผ์ชฝ ํผ์ฐ์ฐ์๊ฐ ์ค์งnull๋๋undefined์ผ ๋๋ง ์ค๋ฅธ์ชฝ ํผ์ฐ์ฐ์๋ฅผ ๋ฐํํฉ๋๋ค.
์ด ์ฐจ์ด์ ์ ๋ช ํํ ํ๊ธฐ ์ํด ์์ ๋ฅผ ์ดํด๋ด ์๋ค:
// Example 1: With 'null' or 'undefined'
const nullValue = null;
const undefinedValue = undefined;
const defaultValue = 'Default Value';
console.log(nullValue || defaultValue); // 'Default Value'
console.log(nullValue ?? defaultValue); // 'Default Value'
console.log(undefinedValue || defaultValue); // 'Default Value'
console.log(undefinedValue ?? defaultValue); // 'Default Value'
// --- Behavior diverges here ---
// Example 2: With 'false'
const falseValue = false;
console.log(falseValue || defaultValue); // 'Default Value' (|| treats false as falsy)
console.log(falseValue ?? defaultValue); // false (?? treats false as a valid value)
// Example 3: With '0'
const zeroValue = 0;
console.log(zeroValue || defaultValue); // 'Default Value' (|| treats 0 as falsy)
console.log(zeroValue ?? defaultValue); // 0 (?? treats 0 as a valid value)
// Example 4: With empty string ''
const emptyString = '';
console.log(emptyString || defaultValue); // 'Default Value' (|| treats '' as falsy)
console.log(emptyString ?? defaultValue); // '' (?? treats '' as a valid value)
// Example 5: With NaN
const nanValue = NaN;
console.log(nanValue || defaultValue); // 'Default Value' (|| treats NaN as falsy)
console.log(nanValue ?? defaultValue); // NaN (?? treats NaN as a valid value)
ํต์ฌ์ ??๊ฐ ๊ธฐ๋ณธ๊ฐ์ ๋ํด ํจ์ฌ ๋ ์ ๋ฐํ ์ ์ด๋ฅผ ์ ๊ณตํ๋ค๋ ๊ฒ์
๋๋ค. ๋ง์ฝ 0, false, ๋๋ ๋น ๋ฌธ์์ด ''์ด ์ ํ๋ฆฌ์ผ์ด์
๋ก์ง์์ ์ ํจํ๊ณ ์๋ฏธ ์๋ ๊ฐ์ผ๋ก ๊ฐ์ฃผ๋๋ค๋ฉด, ||๋ ์ด๋ฅผ ์๋ชป ๋์ฒดํ ๊ฒ์ด๋ฏ๋ก ๊ธฐ๋ณธ๊ฐ์ ์ค์ ํ ๋ ??๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
๊ตฌ๋ฌธ ๋ฐ ์ค์ ์์
1. ๊ธฐ๋ณธ ๊ตฌ์ฑ ๊ฐ ์ค์
์ด๋ ๋ ๋ณํฉ ์ฐ์ฐ์์ ์๋ฒฝํ ์ฌ์ฉ ์ฌ๋ก๋ก, (falsy ๊ฐ์ผ์ง๋ผ๋) ์ ํจํ ๋ช ์์ ์ค์ ์ ๋ณด์กดํ๋ฉด์, ์ ๋ง๋ก ๋๋ฝ๋ ์ค์ ์๋ง ๊ธฐ๋ณธ๊ฐ์ ๋ถ์ฌํฉ๋๋ค.
const userSettings = {
theme: 'light',
fontSize: 14,
enableNotifications: false, // User explicitly set to false
animationSpeed: null // animationSpeed explicitly set to null (perhaps to inherit default)
};
const defaultSettings = {
theme: 'dark',
fontSize: 16,
enableNotifications: true,
animationSpeed: 300
};
const currentTheme = userSettings.theme ?? defaultSettings.theme;
console.log(`Current Theme: ${currentTheme}`); // 'light'
const currentFontSize = userSettings.fontSize ?? defaultSettings.fontSize;
console.log(`Current Font Size: ${currentFontSize}`); // 14 (not 16, because 0 is a valid number)
const notificationsEnabled = userSettings.enableNotifications ?? defaultSettings.enableNotifications;
console.log(`Notifications Enabled: ${notificationsEnabled}`); // false (not true, because false is a valid boolean)
const animationDuration = userSettings.animationSpeed ?? defaultSettings.animationSpeed;
console.log(`Animation Duration: ${animationDuration}`); // 300 (because animationSpeed was null)
const language = userSettings.language ?? 'en-US'; // language is not defined
console.log(`Selected Language: ${language}`); // 'en-US'
2. ์ ํ์ API ๋งค๊ฐ๋ณ์ ๋๋ ์ฌ์ฉ์ ์ ๋ ฅ ์ฒ๋ฆฌ
API ์์ฒญ์ ๊ตฌ์ฑํ๊ฑฐ๋ ์ฌ์ฉ์ ์์ ์ ์ถ์ ์ฒ๋ฆฌํ ๋ ํน์ ํ๋๋ ์ ํ ์ฌํญ์ผ ์ ์์ต๋๋ค. ??๋ ํฉ๋ฒ์ ์ธ 0 ๋๋ false ๊ฐ์ ๋ฎ์ด์ฐ์ง ์์ผ๋ฉด์ ํฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ๊ฐ์ ํ ๋นํ๋ ๋ฐ ๋์์ ์ค๋๋ค.
function searchProducts(query, options) {
const resultsPerPage = options?.limit ?? 20; // Default to 20 if limit is null/undefined
const minPrice = options?.minPrice ?? 0; // Default to 0, allowing actual 0 as a valid min price
const sortBy = options?.sortBy ?? 'relevance';
console.log(`Searching for: '${query}'`);
console.log(` Results per page: ${resultsPerPage}`);
console.log(` Minimum price: ${minPrice}`);
console.log(` Sort by: ${sortBy}`);
}
searchProducts('laptops', { limit: 10, minPrice: 500 });
// Expected:
// Searching for: 'laptops'
// Results per page: 10
// Minimum price: 500
// Sort by: relevance
searchProducts('keyboards', { minPrice: 0, sortBy: null }); // minPrice is 0, sortBy is null
// Expected:
// Searching for: 'keyboards'
// Results per page: 20
// Minimum price: 0
// Sort by: relevance (because sortBy was null)
searchProducts('monitors', {}); // No options provided
// Expected:
// Searching for: 'monitors'
// Results per page: 20
// Minimum price: 0
// Sort by: relevance
๋ ๋ณํฉ ์ฐ์ฐ์์ ์ฃผ์ ์ด์
-
์ ๋ฐํ ๊ธฐ๋ณธ๊ฐ: ์ค์ง ์ง์ ์ผ๋ก ๋๋ฝ๋ ๊ฐ(
null๋๋undefined)๋ง์ด ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋์ฒด๋๋๋ก ๋ณด์ฅํ๋ฉฐ,0,'', ๋๋false์ ๊ฐ์ ์ ํจํ falsy ๊ฐ์ ๋ณด์กดํฉ๋๋ค. -
๋ ๋ช
ํํ ์๋:
null๋๋undefined์ ๋ํด์๋ง ๋์ฒด ๊ฐ์ ์ ๊ณตํ๋ ค๋ ์๋๋ฅผ ๋ช ์์ ์ผ๋ก ๋ํ๋ด์ด ์ฝ๋์ ๋ ผ๋ฆฌ๋ฅผ ๋ ํฌ๋ช ํ๊ฒ ๋ง๋ญ๋๋ค. -
๊ฒฌ๊ณ ํจ:
||๋ฅผ ์ฌ์ฉํ ๋ ํฉ๋ฒ์ ์ธ0์ด๋false๊ฐ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋์ฒด๋ ์ ์๋ ์๋์น ์์ ๋ถ์์ฉ์ ๋ฐฉ์งํฉ๋๋ค. -
๊ธ๋ก๋ฒ ์ ์ฉ์ฑ: ์ด๋ฌํ ์ ๋ฐ์ฑ์
0์ด ์ค์ํ ๊ฐ์ธ ๊ธ์ต ์ ํ๋ฆฌ์ผ์ด์ ์ด๋, ๋น ๋ฌธ์์ด์ด ์๋์ ์ธ ์ ํ์ ๋ํ๋ผ ์ ์๋ ๊ตญ์ ํ ์ค์ ๊ณผ ๊ฐ์ด ๋ค์ํ ๋ฐ์ดํฐ ์ ํ์ ๋ค๋ฃจ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์์ ์ ๋๋ค.
์ต๊ฐ์ ์กฐํฉ: ์ต์ ๋ ์ฒด์ด๋๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์ ํจ๊ป ์ฌ์ฉํ๊ธฐ
์ต์
๋ ์ฒด์ด๋๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์๋ ๊ฐ๊ฐ ๊ฐ๋ ฅํ์ง๋ง, ํจ๊ป ์ฌ์ฉ๋ ๋ ์ง์ ์ผ๋ก ๋น์ ๋ฐํฉ๋๋ค. ์ด ์๋์ง๋ ์ ์ฌ์ ์ผ๋ก ๋๋ฝ๋ ๊ฐ์ฒด ๊ตฌ์กฐ๋ฅผ ์์ ํ๊ฒ ํ์ํ๊ณ , ๋ง์ฝ ์ต์ข
๊ฐ์ด null ๋๋ undefined์ด๋ฉด ์ฆ์ ์๋ฏธ ์๋ ๋์ฒด ๊ฐ์ ์ ๊ณตํจ์ผ๋ก์จ ๋งค์ฐ ๊ฒฌ๊ณ ํ๊ณ ๊ฐ๊ฒฐํ ๋ฐ์ดํฐ ์ ๊ทผ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
์๋์ง ํจ๊ณผ ์์
1. ๊ธฐ๋ณธ ๋์ฒด ๊ฐ์ ์ฌ์ฉํ์ฌ ์ค์ฒฉ ์์ฑ ์ ๊ทผํ๊ธฐ
์ด๊ฒ์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ด๊ณ ์ํฅ๋ ฅ ์๋ ๊ฒฐํฉ ์ฌ์ฉ ์ฌ๋ก์ ๋๋ค.
const userData = {
id: 'user-007',
name: 'James Bond',
contactDetails: {
email: 'james.bond@mi6.gov.uk',
phone: '007-007-0070'
},
// preferences is missing
address: {
street: 'Whitehall St',
city: 'London'
// postcode is missing
}
};
const clientData = {
id: 'client-101',
name: 'Global Ventures Inc.',
location: {
city: 'New York'
}
};
const guestData = {
id: 'guest-999'
};
// Safely get user's preferred language, defaulting to 'en-GB'
const userLang = userData?.preferences?.language ?? 'en-GB';
console.log(`User Language: ${userLang}`); // 'en-GB'
// Get client's country, defaulting to 'Unknown'
const clientCountry = clientData?.location?.country ?? 'Unknown';
console.log(`Client Country: ${clientCountry}`); // 'Unknown'
// Get a guest's display name, defaulting to 'Guest'
const guestDisplayName = guestData?.displayName ?? 'Guest';
console.log(`Guest Display Name: ${guestDisplayName}`); // 'Guest'
// Get user's postcode, defaulting to 'N/A'
const userPostcode = userData?.address?.postcode ?? 'N/A';
console.log(`User Postcode: ${userPostcode}`); // 'N/A'
// What if an explicitly empty string is valid?
const profileWithEmptyBio = {
username: 'coder',
info: { bio: '' }
};
const profileWithNullBio = {
username: 'developer',
info: { bio: null }
};
const bio1 = profileWithEmptyBio?.info?.bio ?? 'No bio provided';
console.log(`Bio 1: '${bio1}'`); // Bio 1: '' (empty string is preserved)
const bio2 = profileWithNullBio?.info?.bio ?? 'No bio provided';
console.log(`Bio 2: '${bio2}'`); // Bio 2: 'No bio provided' (null is replaced)
2. ๋์ฒด ๋์๊ณผ ํจ๊ป ์กฐ๊ฑด๋ถ๋ก ๋ฉ์๋ ํธ์ถํ๊ธฐ
์ด ์กฐํฉ์ ์ฌ์ฉํ์ฌ ๋ฉ์๋๊ฐ ์กด์ฌํ๋ฉด ์คํํ๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด ๊ธฐ๋ณธ ๋์์ ์ํํ๊ฑฐ๋ ๋ฉ์์ง๋ฅผ ๊ธฐ๋กํ ์ ์์ต๋๋ค.
const logger = {
log: (message) => console.log(`[INFO] ${message}`)
};
const analytics = {}; // No 'track' method
const systemEvent = 'application_start';
// Try to track event, otherwise just log it
analytics.track?.(systemEvent, { origin: 'bootstrap' }) ?? logger.log(`Fallback: Could not track event '${systemEvent}'`);
// Expected: [INFO] Fallback: Could not track event 'application_start'
const anotherLogger = {
warn: (msg) => console.warn(`[WARN] ${msg}`),
log: (msg) => console.log(`[LOG] ${msg}`)
};
anotherLogger.track?.('test') ?? anotherLogger.warn('Track method not available.');
// Expected: [WARN] Track method not available.
3. ๊ตญ์ ํ(i18n) ๋ฐ์ดํฐ ์ฒ๋ฆฌ
๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์์ i18n ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ๋ณต์กํ ์ ์์ผ๋ฉฐ, ํน์ ๋ก์ผ์ผ์ ๋ํ ๋ฒ์ญ์ด ๋๋ฝ๋ ์ ์์ต๋๋ค. ์ด ์กฐํฉ์ ๊ฒฌ๊ณ ํ ๋์ฒด ๋ฉ์ปค๋์ฆ์ ๋ณด์ฅํฉ๋๋ค.
const translations = {
'en-US': {
greeting: 'Hello',
messages: {
welcome: 'Welcome!',
error: 'An error occurred.'
}
},
'es-ES': {
greeting: 'Hola',
messages: {
welcome: 'ยกBienvenido!',
loading: 'Cargando...'
}
}
};
function getTranslation(locale, keyPath, defaultValue) {
// Split keyPath into an array of properties
const keys = keyPath.split('.');
// Dynamically access nested properties using optional chaining
let result = translations[locale];
for (const key of keys) {
result = result?.[key];
}
// Provide a default if the translation is null or undefined
return result ?? defaultValue;
}
console.log(getTranslation('en-US', 'messages.welcome', 'Fallback Welcome')); // 'Welcome!'
console.log(getTranslation('es-ES', 'messages.welcome', 'Fallback Welcome')); // 'ยกBienvenido!'
console.log(getTranslation('es-ES', 'messages.error', 'Fallback Error')); // 'Fallback Error' (error is missing in es-ES)
console.log(getTranslation('fr-FR', 'greeting', 'Bonjour')); // 'Bonjour' (fr-FR locale is missing entirely)
์ด ์์ ๋ ?.๊ฐ ์ ์ฌ์ ์ผ๋ก ์กด์ฌํ์ง ์๋ ๋ก์ผ์ผ ๊ฐ์ฒด์ ์ค์ฒฉ๋ ๋ฉ์์ง ํค๋ฅผ ์์ ํ๊ฒ ํ์ํ๊ฒ ํด์ฃผ๊ณ , ??๋ ํน์ ๋ฒ์ญ์ด ๋๋ฝ๋ ๊ฒฝ์ฐ undefined ๋์ ํฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ๊ฐ์ด ์ ๊ณต๋๋๋ก ๋ณด์ฅํ๋ ๋ฐฉ๋ฒ์ ์๋ฆ๋ต๊ฒ ๋ณด์ฌ์ค๋๋ค.
๊ณ ๊ธ ์ฌ์ฉ ์ฌ๋ก ๋ฐ ๊ณ ๋ ค ์ฌํญ
1. ๋จ์ถ ํ๊ฐ ๋์
์ต์
๋ ์ฒด์ด๋์ด ๋จ์ถ ํ๊ฐ๋๋ค๋ ์ ์ ๊ธฐ์ตํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด๋ ์ฒด์ธ์ ํผ์ฐ์ฐ์๊ฐ null ๋๋ undefined๋ก ํ๊ฐ๋๋ฉด ํํ์์ ๋๋จธ์ง ๋ถ๋ถ์ ํ๊ฐ๋์ง ์์์ ์๋ฏธํฉ๋๋ค. ์ด๋ ์ฑ๋ฅ์ ์ด๋กญ๊ณ ๋ถ์์ฉ์ ๋ฐฉ์งํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
let count = 0;
const user = {
name: 'Anna',
getAddress: () => {
count++;
console.log('Fetching address...');
return { city: 'Paris' };
}
};
const admin = null;
// user exists, getAddress is called
console.log(user?.getAddress()?.city); // Output: Fetching address..., then 'Paris'
console.log(count); // 1
// admin is null, getAddress is NOT called
console.log(admin?.getAddress()?.city); // Output: undefined
console.log(count); // Still 1 (getAddress was not executed)
2. ๊ตฌ์กฐ ๋ถํด ํ ๋น๊ณผ ์ต์ ๋ ์ฒด์ด๋ (์ฃผ์ ๊น์ ์ ์ฉ)
const { user?.profile } = data;์ ๊ฐ์ด ๊ตฌ์กฐ ๋ถํด *ํ ๋น*์์๋ ์ต์
๋ ์ฒด์ด๋์ ์ง์ ์ฌ์ฉํ ์ ์์ง๋ง, ๊ฐ์ฒด๋ก๋ถํฐ ๋ณ์๋ฅผ ์ ์ํ๊ณ ๋์ฒด ๊ฐ์ ์ ๊ณตํ ๋๋, ์์ฑ์ ์์ ํ๊ฒ ์ ๊ทผํ ํ์ ๊ตฌ์กฐ ๋ถํด๋ฅผ ํ ๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
const apiResponse = {
success: true,
payload: {
data: {
user: {
id: 'u456',
name: 'David',
email: 'david@example.com'
}
}
}
};
const emptyResponse = {
success: false
};
// Extracting deeply nested data with a default
const userId = apiResponse?.payload?.data?.user?.id ?? 'guest';
const userName = apiResponse?.payload?.data?.user?.name ?? 'Anonymous';
console.log(`User ID: ${userId}, Name: ${userName}`); // User ID: u456, Name: David
const guestId = emptyResponse?.payload?.data?.user?.id ?? 'guest';
const guestName = emptyResponse?.payload?.data?.user?.name ?? 'Anonymous';
console.log(`Guest ID: ${guestId}, Name: ${guestName}`); // Guest ID: guest, Name: Anonymous
// A common pattern is to safely access an object first, then destructure if it exists:
const { user: userDataFromResponse } = apiResponse.payload.data;
const { id = 'default-id', name = 'Default Name' } = userDataFromResponse ?? {};
console.log(`Destructured ID: ${id}, Name: ${name}`); // Destructured ID: u456, Name: David
// For an empty response:
const { user: userDataFromEmptyResponse } = emptyResponse.payload?.data ?? {}; // Use optional chaining for payload.data, then ?? {} for user
const { id: emptyId = 'default-id', name: emptyName = 'Default Name' } = userDataFromEmptyResponse ?? {};
console.log(`Destructured Empty ID: ${emptyId}, Name: ${emptyName}`); // Destructured Empty ID: default-id, Name: Default Name
3. ์ฐ์ฐ์ ์ฐ์ ์์ ๋ฐ ๊ทธ๋ฃนํ
์ต์
๋ ์ฒด์ด๋(?.)์ ๋ ๋ณํฉ ์ฐ์ฐ์(??)๋ณด๋ค ์ฐ์ ์์๊ฐ ๋์ต๋๋ค. ์ด๋ a?.b ?? c๊ฐ (a?.b) ?? c๋ก ํด์๋๋ค๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ, ์ด๋ ์ผ๋ฐ์ ์ผ๋ก ์ํ๋ ๋์์
๋๋ค. ์ด ์กฐํฉ์ ์ํด ์ถ๊ฐ์ ์ธ ๊ดํธ๋ ๋ณดํต ํ์ํ์ง ์์ต๋๋ค.
const config = {
value: null
};
// Correctly evaluates to (config?.value) ?? 'default'
const result = config?.value ?? 'default';
console.log(result); // 'default'
// If the value was 0:
const configWithZero = {
value: 0
};
const resultZero = configWithZero?.value ?? 'default';
console.log(resultZero); // 0 (as 0 is not nullish)
4. ํ์ ๊ฒ์ฌ์์ ํตํฉ (์: TypeScript)
TypeScript๋ฅผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์๋ค์๊ฒ ์ต์ ๋ ์ฒด์ด๋๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์๋ ์๋ฒฝํ๊ฒ ์ง์๋๋ฉฐ ํ์ ์์ ์ฑ์ ํฅ์์ํต๋๋ค. TypeScript๋ ์ด๋ฌํ ์ฐ์ฐ์๋ค์ ํ์ฉํ์ฌ ํ์ ์ ์ ํํ๊ฒ ์ถ๋ก ํ ์ ์์ผ๋ฏ๋ก, ํน์ ์๋๋ฆฌ์ค์์ ๋ช ์์ ์ธ null ํ์ธ์ ํ์์ฑ์ ์ค์ด๊ณ ํ์ ์์คํ ์ ๋์ฑ ๊ฐ๋ ฅํ๊ฒ ๋ง๋ญ๋๋ค.
// Example in TypeScript (conceptual, not runnable JS)
interface User {
id: string;
name: string;
email?: string; // email is optional
address?: {
street: string;
city: string;
zipCode?: string; // zipCode is optional
};
}
function getUserEmail(user: User): string {
// TypeScript understands user.email could be undefined, and handles it with ??
return user.email ?? 'No email provided';
}
function getUserZipCode(user: User): string {
// TypeScript understands address and zipCode are optional
return user.address?.zipCode ?? 'N/A';
}
const user1: User = { id: '1', name: 'John Doe', email: 'john@example.com', address: { street: 'Main', city: 'Town' } };
const user2: User = { id: '2', name: 'Jane Doe' }; // No email or address
console.log(getUserEmail(user1)); // 'john@example.com'
console.log(getUserEmail(user2)); // 'No email provided'
console.log(getUserZipCode(user1)); // 'N/A' (zipCode is missing)
console.log(getUserZipCode(user2)); // 'N/A' (address is missing)
์ด๋ฌํ ํตํฉ์ ์ปดํ์ผ๋ฌ๊ฐ ๋ชจ๋ ์ ํ์ ๋ฐ nullish ๊ฒฝ๋ก๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌ๋๋๋ก ๋ณด์ฅํ๋ ๋ฐ ๋์์ ์ฃผ์ด ๊ฐ๋ฐ์ ๊ฐ์ํํ๊ณ ๋ฐํ์ ์ค๋ฅ๋ฅผ ๋์ฑ ์ค์ฌ์ค๋๋ค.
๋ชจ๋ฒ ์ฌ๋ก ๋ฐ ๊ธ๋ก๋ฒ ๊ด์
์ต์ ๋ ์ฒด์ด๋๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฑํํ๋ ๊ฒ์ ๋จ์ํ ๊ตฌ๋ฌธ์ ์ดํดํ๋ ๊ฒ ์ด์์ ํฌํจํฉ๋๋ค; ํนํ ๊ธ๋ก๋ฒ ๊ณ ๊ฐ์ ๋์์ผ๋ก ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ, ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ฐ ์ฝ๋ ์ค๊ณ์ ๋ํ ์ ๋ต์ ์ ๊ทผ์ด ํ์ํฉ๋๋ค.
1. ๋ฐ์ดํฐ๋ฅผ ํ์ ํ๋ผ
ํญ์ ๋ฐ์ดํฐ์ ์ ์ฌ์ ์ธ ๊ตฌ์กฐ๋ฅผ ์ดํดํ๋ ค๊ณ ๋
ธ๋ ฅํด์ผ ํ๋ฉฐ, ํนํ ์ธ๋ถ ์์ค์์ ์ค๋ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ ๋์ฑ ๊ทธ๋ ์ต๋๋ค. ?.์ ??๋ ์์ ์ฑ์ ์ ๊ณตํ์ง๋ง, ๋ช
ํํ ๋ฐ์ดํฐ ๊ณ์ฝ์ด๋ API ๋ฌธ์์ ํ์์ฑ์ ๋์ฒดํ์ง๋ ์์ต๋๋ค. ํ๋๊ฐ *์์๋๋ก* ์ ํ ์ฌํญ์ด๊ฑฐ๋ ๋๋ฝ๋ ์ ์์ ๋ ์ฌ์ฉํ๊ณ , ์ ์ ์๋ ๋ฐ์ดํฐ ์คํค๋ง์ ๋ํ ํฌ๊ด์ ์ธ ํด๊ฒฐ์ฑ
์ผ๋ก ์ฌ์ฉํ์ง ๋ง์ญ์์ค.
2. ๊ฐ๊ฒฐ์ฑ๊ณผ ๊ฐ๋ ์ฑ์ ๊ท ํ์ ๋ง์ถ๋ผ
์ด๋ฌํ ์ฐ์ฐ์๋ค์ ์ฝ๋๋ฅผ ์งง๊ฒ ๋ง๋ค์ง๋ง, ๊ณผ๋ํ๊ฒ ๊ธด ์ฒด์ธ์ ์ฌ์ ํ ์ฝ๊ธฐ ์ด๋ ค์์ง ์ ์์ต๋๋ค. ๋งค์ฐ ๊น์ ์ ๊ทผ ๊ฒฝ๋ก๋ ๋๋๊ฑฐ๋, ๋ช ํ์ฑ์ ํฅ์์ํจ๋ค๋ฉด ์ค๊ฐ ๋ณ์๋ฅผ ๋ง๋๋ ๊ฒ์ ๊ณ ๋ คํ์ญ์์ค.
// Potentially less readable:
const userCity = clientRequest?.customer?.billing?.primaryAddress?.location?.city?.toUpperCase() ?? 'UNKNOWN';
// More readable breakdown:
const primaryAddress = clientRequest?.customer?.billing?.primaryAddress;
const userCity = primaryAddress?.location?.city?.toUpperCase() ?? 'UNKNOWN';
3. '๋๋ฝ'๊ณผ '๋ช ์์ ์ธ ๋น ๊ฐ/0'์ ๊ตฌ๋ณํ๋ผ
์ด๊ฒ์ด ??๊ฐ ์ง์ ์ผ๋ก ๋น์ ๋ฐํ๋ ๋ถ๋ถ์
๋๋ค. ๊ตญ์ ์ ์ธ ์์์ด๋ ๋ฐ์ดํฐ ์
๋ ฅ์์ ์ฌ์ฉ์๋ ์๋์ '0', ๋ถ์ธ ์ค์ ์ 'false', ๋๋ ์ ํ์ ๋๊ธ์ ๋น ๋ฌธ์์ด ''์ ๋ช
์์ ์ผ๋ก ์
๋ ฅํ ์ ์์ต๋๋ค. ์ด๊ฒ๋ค์ ์ ํจํ ์
๋ ฅ์ด๋ฉฐ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋์ฒด๋์ด์๋ ์ ๋ฉ๋๋ค. ??๋ ์ด๋ฌํ ์ ๋ฐ์ฑ์ ๋ณด์ฅํ์ง๋ง, ||๋ ์ด๋ฅผ ๊ธฐ๋ณธ๊ฐ์ ํธ๋ฆฌ๊ฑฐ๋ก ์ทจ๊ธํ ๊ฒ์
๋๋ค.
4. ์ค๋ฅ ์ฒ๋ฆฌ: ์ฌ์ ํ ํ์์
์ต์
๋ ์ฒด์ด๋์ null/undefined ์ ๊ทผ์ ๋ํ TypeError๋ฅผ ๋ฐฉ์งํ์ง๋ง, ๋ค๋ฅธ ์ ํ์ ์ค๋ฅ(์: ๋คํธ์ํฌ ์ค๋ฅ, ์๋ชป๋ ํจ์ ์ธ์, ๋ก์ง ์ค๋ฅ)๋ฅผ ๋ฐฉ์งํ์ง๋ ์์ต๋๋ค. ๊ฒฌ๊ณ ํ ์ ํ๋ฆฌ์ผ์ด์
์ ์ฌ์ ํ ๋ค๋ฅธ ์ ์ฌ์ ๋ฌธ์ ์ ๋ํด try...catch ๋ธ๋ก๊ณผ ๊ฐ์ ํฌ๊ด์ ์ธ ์ค๋ฅ ์ฒ๋ฆฌ ์ ๋ต์ด ํ์ํฉ๋๋ค.
5. ๋ธ๋ผ์ฐ์ /ํ๊ฒฝ ์ง์์ ๊ณ ๋ คํ๋ผ
์ต์ ๋ ์ฒด์ด๋๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์๋ ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ธฐ๋ฅ(ES2020)์ ๋๋ค. ํ๋์ ์ธ ๋ธ๋ผ์ฐ์ ์ Node.js ๋ฒ์ ์์๋ ๋๋ฆฌ ์ง์๋์ง๋ง, ์ค๋๋ ํ๊ฒฝ์ ๋์์ผ๋ก ํ๋ ๊ฒฝ์ฐ Babel๊ณผ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋๋ฅผ ํธ๋์คํ์ผํด์ผ ํ ์๋ ์์ต๋๋ค. ํญ์ ๋์ ๊ณ ๊ฐ์ ๋ธ๋ผ์ฐ์ ํต๊ณ๋ฅผ ํ์ธํ์ฌ ํธํ์ฑ์ ๋ณด์ฅํ๊ฑฐ๋ ํธ๋์คํ์ผ ๊ณํ์ ์ธ์ฐ์ญ์์ค.
6. ๊ธฐ๋ณธ๊ฐ์ ๋ํ ๊ธ๋ก๋ฒ ๊ด์
๊ธฐ๋ณธ๊ฐ์ ์ ๊ณตํ ๋๋ ๊ธ๋ก๋ฒ ๊ณ ๊ฐ์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด:
- ๋ ์ง์ ์๊ฐ: ํน์ ์๊ฐ๋๋ ํ์์ผ๋ก ๊ธฐ๋ณธ๊ฐ์ ์ค์ ํ๋ ๊ฒ์ ์ฌ์ฉ์ ์์น๋ฅผ ์ผ๋์ ๋์ด์ผ ํฉ๋๋ค.
- ํตํ: ๊ธฐ๋ณธ ํตํ(์: USD)๊ฐ ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ์ ์ ํ์ง ์์ ์ ์์ต๋๋ค.
- ์ธ์ด: ํน์ ๋ก์ผ์ผ์ ๋ฒ์ญ์ด ๋๋ฝ๋ ๊ฒฝ์ฐ ํญ์ ํฉ๋ฆฌ์ ์ธ ๋์ฒด ์ธ์ด(์: ์์ด)๋ฅผ ์ ๊ณตํด์ผ ํฉ๋๋ค.
- ์ธก์ ๋จ์: '๋ฏธํฐ๋ฒ' ๋๋ '์ผ๋ํ์ด๋๋ฒ'์ผ๋ก ๊ธฐ๋ณธ๊ฐ์ ์ค์ ํ๋ ๊ฒ์ ๋ฌธ๋งฅ์ ์ธ์ํด์ผ ํฉ๋๋ค.
์ด๋ฌํ ์ฐ์ฐ์๋ค์ ๊ทธ๋ฌํ ๋ฌธ๋งฅ ์ธ์ ๊ธฐ๋ณธ๊ฐ์ ์ฐ์ํ๊ฒ ๊ตฌํํ๋ ๊ฒ์ ๋ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
๊ฒฐ๋ก
์๋ฐ์คํฌ๋ฆฝํธ์ ์ต์
๋ ์ฒด์ด๋(?.)๊ณผ ๋ ๋ณํฉ ์ฐ์ฐ์(??)๋ ๋ชจ๋ ํ๋ ๊ฐ๋ฐ์์๊ฒ ํ์์ ์ธ ๋๊ตฌ์
๋๋ค. ์ด๋ค์ ๋ณต์กํ ๊ฐ์ฒด ๊ตฌ์กฐ์์ ์ ์ฌ์ ์ผ๋ก ๋๋ฝ๋๊ฑฐ๋ ์ ์๋์ง ์์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ๊ณผ ๊ด๋ จ๋ ์ผ๋ฐ์ ์ธ ๋ฌธ์ ์ ๋ํด ์ฐ์ํ๊ณ , ๊ฐ๊ฒฐํ๋ฉฐ, ๊ฒฌ๊ณ ํ ํด๊ฒฐ์ฑ
์ ์ ๊ณตํฉ๋๋ค.
์ต์
๋ ์ฒด์ด๋์ ํ์ฉํจ์ผ๋ก์จ, ์ ํ๋ฆฌ์ผ์ด์
์ ์ค๋จ์ํค๋ TypeErrors์ ๋ํ ๋๋ ค์ ์์ด ๊น์ ์์ฑ ๊ฒฝ๋ก๋ฅผ ์์ ํ๊ฒ ํ์ํ๊ณ ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค. ๋ ๋ณํฉ ์ฐ์ฐ์๋ฅผ ํตํฉํจ์ผ๋ก์จ, ๊ธฐ๋ณธ๊ฐ์ ๋ํ ์ ๋ฐํ ์ ์ด๋ฅผ ์ป๊ฒ ๋์ด ์ค์ง ์ง์ ํ null ๋๋ undefined ๊ฐ๋ง์ด ๋์ฒด๋๊ณ 0์ด๋ false์ ๊ฐ์ ํฉ๋ฒ์ ์ธ falsy ๊ฐ์ ๋ณด์กด๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
ํจ๊ป, ์ด "์ต๊ฐ์ ์กฐํฉ"์ ์ฝ๋ ๊ฐ๋ ์ฑ์ ๊ทน์ ์ผ๋ก ํฅ์์ํค๊ณ , ์์ฉ๊ตฌ ์ฝ๋๋ฅผ ์ค์ด๋ฉฐ, ๋ค์ํ ๊ธ๋ก๋ฒ ํ๊ฒฝ์์ ์ค์ ๋ฐ์ดํฐ์ ์์ธก ๋ถ๊ฐ๋ฅํ ํน์ฑ์ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ๋ ๋ ํ๋ ฅ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ด์ด์ง๋๋ค. ์ด๋ฌํ ๊ธฐ๋ฅ์ ์์ฉํ๋ ๊ฒ์ ๋ ๊นจ๋ํ๊ณ , ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ฐ๋ฉฐ, ๋งค์ฐ ์ ๋ฌธ์ ์ธ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ช ํํ ๋จ๊ณ์ ๋๋ค. ์ค๋ ๋ฐ๋ก ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ์ ํตํฉํ์ฌ ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ์ํ ์ง์ ์ผ๋ก ๊ฒฌ๊ณ ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ์ด๋ค ์ฐจ์ด๋ฅผ ๋ง๋๋์ง ๊ฒฝํํด ๋ณด์ญ์์ค!