프론트엔드 개발자가 알아두면 유용한 JS 문법들 - 1편

2022. 3. 29. 11:04Javascript

728x90

개발을 하다 보면 특히 많이 쓰게 되는 문법들이나 연산자들이 있습니다. 

 

이번 포스트에서는 필자가 유용하게 쓰는 자바스크립트 기본 문법 및 기능들 (ES6+ 포함)에 대해 알아보도록 하겠습니다. 이미 다 알고 있는 분들도 많겠지만 그런 분들은 내가 어느 정도 아는지에 대한 체크리스트 정도로 생각해주시고 아직 생소하신 분들에게는 좀 더 간결하고 효과적인 방법으로 개발할 수 있는 계기가 되었으면 합니다.

 

이외에도 공유하고 싶은게 있다면 댓글로 꼭 남겨주시길 바랍니다. 


타입 변환 (Type Casting)

10 + "" -> 문자 ("10")
+ "10" -> 숫자 (10)
!!10 -> 불리언 (true)

 

폼을 다루거나 서버에서 받아온 데이터를 가지고 특정 작업을 할 때 타입 변환을 해야 하는 경우가 많습니다.

 

이때 생성자 함수에 new 연산자를 생략해서 사용하거나  생성자 함수 프로토타입 메서드 (toString, parseInt) 등을 사용해서 명시적으로 타입 변환을 해주는 경우가 많습니다. 

 

필자도 팀 프로젝트에서는 팀원들이 이해할수 있고 예측 가능한 코드를 짜기 위해 명시적 타입 변환을 사용하는 편이지만 개인 프로젝트를 진행하거나 팀원들 동의하에 아래와 같이 자바스크립트 특성을 이용해 암묵적 타입 변환을 하는 경우가 있습니다. 

 

const stringOne = 1 + "";
console.log(`타입: ${typeof stringOne}`, `값: ${stringOne}`); // 타입: string 값: 1

const arrayToString = [1,2] + "";
console.log(`타입: ${typeof arrayToString}`, `값: ${arrayToString}`); // 타입: string 값: 1,2

const numberOne = + "1";
console.log(`타입: ${typeof numberOne}`, `값: ${numberOne}`); // 타입: number 값: 1

const arrayToNumber = +[];
console.log(`타입: ${typeof arrayToNumber}`, `값: ${arrayToNumber}`); 타입: number값: 0

const booleanOne = !!1;
console.log(`타입: ${typeof booleanOne}`, `값: ${booleanOne}`); // 타입: boolean값: true

 

물론 자바스크립트 엔진이 어떤식으로 타입 변환하는지 제대로 이해하지 않고 사용한다면 버그가 생겼을 때 어느 부분에서 발생했는지 추적하기 어려워질 수 있다는 단점이 있습니다. 하지만 자바스크립트의 특성을 제대로 이해한 개발자라면 처음에 언급한 명시적 타입 변환만큼이나 명시적인 방법이라고 생각이 되고, 해당 방식으로 작성된 코드도 종종 볼 수 있기에 알아두면 좋겠습니다.

 


삼항 연산자 (Tenery Operator)

조건문 ? 조건문이 참으로 평가될때 실행할 선택문 : 조건문이 거짓일때 실행할 선택문

 

삼항 연산자는위와 같은 형식으로 if else문을 간결하게 작성할 수 있도록 해줍니다. 변수의 값을 조건에 따라 다르게 할당해줘야 하는 경우 사용하거나 리액트 같은 라이브러리를 사용한다면 조건에 따라 다른 컴포넌트 랜더링 해야 할 때 유용하게 사용할 수 있습니다.

 

 // ...생략
 // 인증이된 상태라면 <SignedInContent/> 그렇지 않으면 Home 컴포넌트 랜더링
 { currentUser.isAuthed ? <SignedInContent/> : <Home/> }

 

삼항 연산자를 중첩해서 사용할 순 있지만 너무 길어지면 if else문을 사용하는 것보다 가독성이 현저히 떨어지므로 적절히 중첩하여 사용하는 것을 권장합니다.

 

필자는 보통 아래와 같이 로딩 처리까지는 중첩해서 작성하는 편입니다.

 

loading ? <Loading/> : currentUser.isAuthed ? <SignedInContent/> : <Home/>

단축 평가 (Short Circuit Evaulation)

논리연산자 (Logical Operator)

true && true // true
false || true // true

 

논리곱(&&)과 논리합(| |)은 자바스크립트만의 고유 연산자는 아니지만 프런트엔드 개발자로 일하다 보면 사실상 가장 많이 쓰게 되는 연산자 중 하나라고 생각합니다.

 

보통 서버에서 데이터를 불러오거나 DOM 트리를 구축하기전까지 어느 정도 시간이 소요되기 때문에 그 이전에 데이터 값이 할당되어 있지 않은 객체의 프로퍼티 값을 참조하거나 DOM요소를 선택하려고 하면 cannot read property of undefined 에러가 발생합니다. 이 에러는 메시지 그대로 아직 정해지지 않은 값의 프로퍼티를 참조하려 했기 때문에 발생하는 에러이기에  아래와 같이 논리곱 연산자로 값이 있을 때만 참조를 하거나 논리합 연산자로 값이 없을 때 우측에 truthy 한 값으로 평가되는 값을 기본값으로 사용하도록 작성해줄 수 있습니다. Truthy 한 값과 Falsy 한 값이 뭔지 잘 모르겠다면 mdn 문서를 참고해주세요.

 

const name = user && user.name; // user가 falsy한 값이 아닌 경우 우측의 프로퍼티 참조를 이어나가도록 단축평가
const nickname = user.nickname || "mingeegee" // user.nickname 이 falsy한 값일 경우 우측 truthy한 값인 문자열 반환

 

옵셔널 체이닝 (Optional Chaining) - ES2020

obj.val?.prop
obj.val?.[expr]
obj.arr?.[index]
obj.func?.(args)

 

비교적 최신 문법이지만 필자를 비롯한 많은 개발자들이 유용하게 쓰고 있는 연산자입니다. 기존 프로퍼티 참조를 위해 사용되는 (.) 연산자와 같은 역할을 하지만 참조할 프로퍼티 값이 null 또는 undefined일 경우 에러를 발생시키지 않고 undefined을 반환해줍니다. 

 

예를 들어 모든 사용자가 중간 이름을 가지진 않기 때문에 해당 필드는 선택적으로 받아서 저장해두었다고 가정했을 때 아래와 같은 방법으로 참조를 이어나가면 에러가 뜰 것입니다.

 

const middleName = user.name.middleName

 

이때 위에서 언급한 논리 연산자를 사용하는 방법도 있겠지만 옵셔널 체이닝을 사용해서 간결하게 작성할 수 있습니다.

 

const middleName = user?.name?.middleName //  논리 연산자를 사용할 경우 -> user && user.name && user.name.middleName

 

함수와 배열 또한 객체이기 때문에 옵셔널체 이닝을 이용한 프로퍼티 참조가 가능합니다.

 

// 배열

{items.map?.(item => ....)
// 함수, 메서드

const obj = {
  method1: () => '코딩마차'
};

console.log(obj.method1?.()); // 코딩마차
console.log(obj.method2?.()); // undefined

 

 


 

 Nullish 병합 연산자 (Nullish Coalescing Operator) - ES2020

null ?? "기본값" // "기본값"
undefined ?? "기본값" // "기본값"

0 ?? "기본값" // 0
"" ?? "기본값" // ""

 

해당 연산자도 옵셔널체 이닝과 함께 ES2020에 추가되었습니다. 논리합 (| |) 연산자와 유사하게 사용되지만 가장 큰 차이점은 좌항에 falsy한값으로 평가되는 표현식 (대표적으로 0과 "")이 들어와도 그 값이 undefined 또는 null이 아닌 경우 우항의 표현식을 반환하지 않는다는 점입니다. 좌항에 들어오는 표현식이 nullish (undefined 또는 null)로 평가되는 경우에만 우항의 표현식을 반환하기 때문에 확실하게 비어있는 값에 한해서 초기값을 할당해줄 때 유용하게 사용할 수 있습니다.


스프레드 문법 (Spread) - ES6

[ 1, 2, 3, ...iterableObj ]
func(...argument)

Spread라는 단어 그대로 문자열, 배열 등 순회 가능한 객체 (이 터러블)을 개별 요소로 펼칠 수 있는 ES6 문법입니다. ES9에서 이 트러블이 아닌 객체에도 spread를 사용할 수 있게 되었습니다 해당 문법을 어떤식으로 사용할수 있는지 한번 살펴보겠습니다.

 

 

배열 복사 (Copy Array) - ES6

const arr = [1,2]; 
const arrCopy = [...arr]; // [1,2] arr의 얕은 복사

// const [...arrCopy] = [1,2]; // 이후에 언급할 구조분해를 이용한 얉은 복사도 가능

 

배열 병합 (Concat Array) - ES6

const arr1 = [1,2,3]; 
const arr2 = [4,5,6]; 

const arrOrder = [...arr1, ...arr2];  // [1,2,3,4,5,6]
const arrReverse = [...arr2, ...arr1]; // [4,5,6,1,2,3]

 

 

배열의 개별 값을 함수의 인자로 전달 - ES6

const sum = (a, b, c) => a + b + c;
sum(...[1,2,3]); // 6

 

 

 배열 구조 분해 할당 (Array Destructuring) - ES6

const [one, two, ...remaining] = [1, 2, 3, 4];
console.log(one); // 1
console.log(two); // 2
console.log(remaining); // [3,4]

// React의 useState도 배열 구조할당을 사용하고있습니다 const [data, setData] = useState(initValue);

객체 복사  (Copy Object) - ES9

const user = {name: 'Min'}; 
const userCopy = {...user};  // { name:"Min"}

// 구조분해 할당을 통해 얉은 복사 const {...userCopy} = user;

 

객체 병합  - (Concat Object) - ES9

const user = {
    name : "Min",
    occupation: "FE Developer",
    stack: "React"
}

const newUserOrder = {
    ...user,
    stack: "Next",
}

const newUserReverse = {
	stack: "Next",
    ...user,
}

// 중복 필드일경우 마지막 필드로 덮어씌워지기 때문에 주의
console.log(newUserOrder); // { name:"Min", occupation:"FE Developer", stack:"Next" }
console.log(newUserReverse); // { stack:"React", name:"Min", occupation:"FE Developer" }

 

객체 구조분해할당  - (Object Destructuring) - ES9

const { userName, ...stacks } = { userName: "Min", stack: "React", stack2: "Next", stack3: "Firebase" };

console.log(userName); // "Min"
console.log(stacks); // { stack:"React", stack2:"Next", stack3:"Firebase"}

 

스프레드 연산자와 앞서 언급한 논리 연산자를 이용한 단축 평가를 조합해서 사용하면 불필요하게 긴 조건식을 통해서 객체를 정의할 필요가 없이 아래와 같이 간결하게 작성 가능합니다.

 

const buildingInfo = { 
    buildingName: "JAHA",
    ...(isApartment && { hasLift: true }),
  }
  
  // isApartment가 참일때만 hasLift: true라는 키, 값이 추가되고 거짓일경우 아무것도 추가되지않는다

 

포스트가 길어지는 관계로 나머지 문법들은 2편에서 찾아 뵙도록 하겠습니다.