변수와 스코프 (let, const)
var는 버그를 유발하기 쉬워 더 이상 사용하지 않음. 혹 동료가 var를 사용하고 있다면 거침없는 하이킥으로..
const maxPoints = 100; // 변경 불가
let currentScore = 0; // 변경 가능
currentScore += 10;
객체 초기화 단축 성격 (Property Shorthand)
const name = 'Sora';
const age = 28;
// 과거 방식
const user = { name: name, age: age };
// 최신 방식 (똑같이 동작합니다)
const user = { name, age };
구조를 분해해서 할당 (구조분해할당, Destructuring Assignment)
const user = { name: 'Alice', age: 30, city: 'Seoul' };
// 객체 구조 분해
const { name, age } = user;
console.log(name, age); // Alice 30
const { name: name2, ...sss } = user;
console.log(name2, sss); // Alice { age: 30, city: 'Seoul' }
// 다른 이름으로 할당하거나 기본값 설정도 가능
const { name: fullName, email = 'noemail@example.com' } = user;
console.log(fullName, email); // Alice noemail@example.com
// 배열 구조 분해
const colors = ['red', 'green', 'blue'];
const [first, second, third] = colors;
console.log(first, second, third); // red green blue
화살표 함수 (Arrow Functions)
화살표 함수는 this에 대한 유지력이 발생
// 기존 방식
function add(a, b) {
return a + b;
}
// 화살표 함수 (최신)
const add = (a, b) => a + b;
구성 요소를 펼쳐 사용하는 문법 (스프레드 문법, Spread Syntax)
/* 배열 결합 및 복사에서의 예 */
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
// 배열 결합
const combinedArr = [...arr1, ...arr2];
console.log(combinedArr); // [1, 2, 3, 4, 5, 6]
// 배열 복사 (얕은 복사)
const copiedArr = [...arr1];
console.log(copiedArr); // [1, 2, 3]
/* 객체 병합 및 복사에서의 예 */
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
// 객체 병합
const combinedObj = { ...obj1, ...obj2 };
console.log(combinedObj); // { a: 1, b: 2, c: 3, d: 4 }
// 객체 복사 (얕은 복사)
const copiedObj = { ...obj1 };
console.log(copiedObj); // { a: 1, b: 2 }
/* 함수 인자 전달에서의 예 */
function sum(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6 (배열 요소를 개별 인자로 펼쳐서 전달)
// 나머지: 모으기
function sum2(first, ...rest) {
return rest.reduce((acc, v) => acc + v, first);
}
console.log(sum2(1, 2, 3, 4)); // 출력 : 10
null 또는 undefine이 아닐 경우에 대한 선택적 체이닝(선택적 체이닝, Optional Chaining)
const user = {
name: 'Dave',
address: {
street: '123 Main St',
city: 'Busan'
},
// phone: '010-1234-5678' // phone 속성이 없을 수 있음
};
// 기존 방식 (에러 방지)
let city = user.address && user.address.city;
console.log(city); // Busan
let zipCode;
if (user.address && user.address.zipCode) {
zipCode = user.address.zipCode;
}
console.log(zipCode); // undefined
// 선택적 체이닝
const userCity = user.address?.city;
console.log(userCity); // Busan
const userPhone = user.phone?.number; // user.phone이 undefined이므로 userPhone은 undefined
console.log(userPhone); // undefined
const userStreet = user.address?.street;
console.log(userStreet); // 123 Main St
// 배열 요소에도 적용 가능
const arr = [{ value: 10 }];
const firstValue = arr?.[0]?.value;
console.log(firstValue); // 10
const emptyArr = [];
const nonExistentValue = emptyArr?.[0]?.value;
console.log(nonExistentValue); // undefined
// 매서드도 가능함
console.log?.("....");
진짜 null 또는 undefine에 대한 선택 연산자 (Nullish 병합 연산자, Nullish Coalescing Operator)
const userInput = null;
const defaultValue = 'default value';
// || 연산자 (Falsy 값도 걸러냄)
const resultOr = userInput || defaultValue;
console.log(resultOr); // default value
const zeroValue = 0;
const resultOrZero = zeroValue || defaultValue;
console.log(resultOrZero); // default value (0도 Falsy로 간주하여 default value가 할당됨)
// ?? 연산자 (null 또는 undefined만 걸러냄)
const resultNullish = userInput ?? defaultValue;
console.log(resultNullish); // default value
const zeroValueNullish = 0;
const resultNullishZero = zeroValueNullish ?? defaultValue;
console.log(resultNullishZero); // 0 (0은 유효한 값으로 간주됨)
const emptyString = '';
const resultNullishEmptyString = emptyString ?? defaultValue;
console.log(resultNullishEmptyString); // ''
비동기 처리 ( async / await )
async function fetchData() {
try {
const res = await fetch("https://api.example.com/data");
const data = await res.json();
console.log(data);
} catch (err) {
console.error(err);
}
}
최신 배열 / 객체 메서
// 배열
[1, 2, 3].at(-1); // 3 (뒤에서 인덱스)
[1, [2, [3]]].flat(Infinity); // [1, 2, 3]
[1, 2, 3].flatMap(x => [x, x * 2]); // [1,2, 2,4, 3,6]
// 객체
Object.entries({ a: 1, b: 2 }); // [["a",1], ["b",2]]
Object.fromEntries([["a", 1]]); // { a: 1 }
Object.hasOwn(obj, "key"); // true/false (ES2022)
기존 .sort()나 .reverse()는 원본 배열 자체를 바꾸어 버려서 버그를 자주 유발했습니다. 최신 메서드는 원본은 그대로 두고, 정렬된 ‘새로운 배열’을 반환합니다.
const numbers = [3, 1, 4];
const sorted = numbers.toSorted();
console.log(numbers); // [3, 1, 4] (원본 유지!)
console.log(sorted); // [1, 3, 4] (새 배열)
논리 할당 연산자
a ||= "기본값"; // a가 falsy면 할당
a &&= "새값"; // a가 truthy면 할당
a ??= "기본값"; // a가 null/undefined면(truthy와 다름) 할당
Promise 관련
// 모두 성공해야 통과
await Promise.all([p1, p2, p3]);
// 하나라도 완료되면 통과
await Promise.race([p1, p2]);
// 성공/실패 관계없이 전부 기다림
await Promise.allSettled([p1, p2]);
// 하나라도 성공하면 통과
await Promise.any([p1, p2])
for…of / for…in
for (const item of [1, 2, 3]) { } // 값 순회
for (const key in { a: 1, b: 2 }) { } // 키 순회
최상위 await (Top-level await)
예전에는 await 키워드를 쓰려면 무조건 async 함수 내부에서만 감싸서 사용해야 했습니다. 이제는 모듈 시스템(import/export를 쓰는 환경) 파일의 가장 바깥쪽(Top-level)에서도 async 함수 없이 바로 await를 쓸 수 있습니다.
const response = await fetch('https://api.example.com/config');
export const config = await response.json();