자바스크립트 스타일 가이드 학습하기 #3 (Airbnb) - 모듈, 이터레이터, 속성, 변수

REASON·2022년 11월 5일
0

STUDY

목록 보기
110/127

에어 비앤비 코드 스타일 가이드 공부 3일차

에어 비앤비 코드 스타일 학습 1일차 (객체, 배열)
에어 비앤비 코드 스타일 학습 2일차 (문자열, 함수, 화살표 함수, 클래스, 생성자)

오늘은 모듈 파트부터 학습하기!

모듈

importexport 을 사용하자.
하지만 Node 옛날 버전을 사용하는 경우엔 import, export를 사용할 수 없어서 어쩔수 없이 require를 사용해야 하는 상황도 있을 것 같다.

// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;

// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;

// best
import { es6 } from './AirbnbStyleGuide';
export default es6;

import export 며칠 전에 공부했었는데
확실히 module.exports 보다 코드가 예뻐서 좋다!

와일드 카드(*) import를 사용하지 말자.

// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';

// good
import AirbnbStyleGuide from './AirbnbStyleGuide';

export defaut로 내보낸 경우엔 하나의 모듈임이 확실해서 와일드카드를 사용하지 않고 불러올 수 있어서 그런가보다.
export로 여러개 보내는 경우에도 해당이 되나?

import와 export를 분리해서 사용하자

// bad
// filename es6.js
export { es6 as default } from './AirbnbStyleGuide';

// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;

export { ~ as default } from 으로 사용하는 경우가 있구나.. 생소해서 처음 알았다.
한 줄로 표현하려면 저런 표현을 사용할 수도 있다니.
물론 에어비앤비 컨벤션을 따르려면 몰라도 되는 것 같지만.. 저런 것도 되는구나~정도로 알고 넘어가기로 했다.

가변적인 경우 export를 하지 말자

상수인 경우에만 export를 하도록!

// bad
let foo = 3;
export { foo };

// good
const foo = 3;
export { foo };

변수를 내보낼 생각은 한번도 해본 적 없지만 앞으로도 안 하는게 좋겠다.

한가지만 export 하는 경우 export default 를 사용하자.

// bad
export function foo() {}

// good
export default function foo() {}

export default를 쓰면 모듈 하나만 있다는 것이 명시되기 때문에 그런가보다.

import는 호이스팅된다.

와 이건 진짜 처음 알았다.
당연히 import를 상단에 쓰는게 관례처럼 쓰이니까 나도 그렇게써야지~ 해서 생각해본 적도 없었는데
import도 호이스트가 일어나는구나.

// bad
import foo from 'foo';
foo.init();

import bar from 'bar';

// good
import foo from 'foo';
import bar from 'bar';

foo.init();

여러줄 import는 들여쓰기를 사용하자.

// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';

// good
import {
  longNameA,
  longNameB,
  longNameC,
  longNameD,
  longNameE,
} from 'path';

1줄짜리 코드 보니까 갑자기 떠오르는 사람이 있다...
한줄 코드 멈춰 ㅠㅠ
여러줄로 넘긴다고 해도 들여쓰기 예쁘게 해주자.
물론 이런건 프리티어가 알아서 잘 해주겠지만.

import에서 Webpack loader 구문 사용 금지

// bad
import fooSass from 'css!sass!foo.scss';
import barCss from 'style!css!bar.css';

// good
import fooSass from 'foo.scss';
import barCss from 'bar.css';

이 코드 보고 이게 뭐지..? 하는 중.
도대체 css!sass! 이건 뭘까.
코린이가 보기엔 마치 css와 sass를 응원하는 것처럼 보인다.
웹팩을 공부해야겠다는 생각이 드는 순간이다.

자바스크립트 확장자 명시 금지

// bad
import foo from './foo.js';
import bar from './bar.jsx';
import baz from './baz/index.jsx';

// good
import foo from './foo';
import bar from './bar';
import baz from './baz';

확장자 명시는 자율적으로 해도되고, 안해도 되고~ 라고만 생각했는데 확장자 명시는 안하는 쪽이 더 권장되는구나.

이터레이터와 제너레이터

이터레이터 사용 금지

for-infor-of 루프 대신 배열 내장 메서드인 map, reduce, filter 등을 사용하자.

const numbers = [1, 2, 3, 4, 5];

// bad
let sum = 0;
for (let num of numbers) {
  sum += num;
}
sum === 15;

// good
let sum = 0;
numbers.forEach((num) => {
  sum += num;
});
sum === 15;

// best (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;

// bad
const increasedByOne = [];
for (let i = 0; i < numbers.length; i++) {
  increasedByOne.push(numbers[i] + 1);
}

// good
const increasedByOne = [];
numbers.forEach((num) => {
  increasedByOne.push(num + 1);
});

// best (keeping it functional)
const increasedByOne = numbers.map(num => num + 1);

와 왜 for..in for..of 쓰지 말라는거지? 하고 깜짝 놀랐던 부분.. for..in 이나 for...of 최소 한번 이상은 사용했었는데 물론 forEach를 더 많이 썼지만 가끔 for...of 한번 써볼까 싶었던 적도 있었는데..

불변성을 지키는 것이 좋다는 것은 알고 있었지만,
for-in, for-of 를 사용 안 하는게 좋다는 게 너무 충격적이다..ㅠㅠ

쓰지 말라는데는 다 이유가 있겠지.

제너레이터는 아직 쓰지 말자.

지금도 해당되는 사항인지는 모르겠지만, ES5로 트랜스파일이 잘 안된다고 적혀있다.
제너레이터에 대해서는 잘 모르기 때문에 추가적인 학습이 필요할 것같다. 메모해놓고 다음에 제너레이터를 공부해봐야겠다.

속성

속성에 접근할 때는 . 를 사용하자.

const luke = {
  jedi: true,
  age: 28,
};

// bad
const isJedi = luke['jedi'];

// good
const isJedi = luke.jedi;

변수가 key 값인 경우 [] 를 사용하자.

const luke = {
  jedi: true,
  age: 28,
};

function getProp(prop) {
  return luke[prop];
}

const isJedi = getProp('jedi');

제곱 계산할 때는 ** 를 사용하자.

// bad
const binary = Math.pow(2, 10);

// good
const binary = 2 ** 10;

Math.pow 보다 **를 사용하는 게 더 나은가?
자세한 설명은 안 적혀있어서 일단은 그런가보다.. 하고 넘어가야 될 것 같다.

변수

변수 선언 시에는 항상 const 또는 let을 사용하자.

// bad
superPower = new SuperPower();

// good
const superPower = new SuperPower();

변수 선언 없이 저렇게 쓰면 var로 선언하겠다는 건가..

하나의 변수에는 하나의 const 또는 let

// bad
const items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';

// bad
// (위 코드와 비교해 실수를 짚어보세요)
const items = getItems(),
    goSportsTeam = true;
    dragonball = 'z';

// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';

개인적으로 정말 싫어하는 코드 중 하나가 var, let, const 키워드 하나에 여러개의 변수를 이어서 선언하는 거다.
귀찮긴 해도 const랑 let 하나씩 작성해주는 게 더 예쁜 것 같다.

근데 다른 언어 쓸 때는 사실 본인도 하나에 여러개 때려박아서 쓰는 경우도 있어서 할 말이 없지만 ㅋㅋㅋ like int A, B, C; ㅋㅋㅋ
다른 언어로 알고리즘 문제 풀때 무조건 쓰게 되지만, 자바스크립트에서 만큼은 안 쓰게 된다.
뭔가 매우 불편..ㅠㅠ

변수의 선언 순서는 const부터, 그리고 let

// bad
let i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

// bad
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;

// good
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;

bad 코드는 뭔가 뒤죽박죽 섞여있는 느낌이 들긴 한데 그러면 let부터 선언할 수도 있지 않을까 싶지만, const 부터 선언하는 것이 더 권장되는 것 같다.

변수를 선언할 때는 적절한 곳에 놓자.

// bad - unnecessary function call
function checkName(hasName) {
  const name = getName();

  if (hasName === 'test') {
    return false;
  }

  if (name === 'test') {
    this.setName('');
    return false;
  }

  return name;
}

// good
function checkName(hasName) {
  if (hasName === 'test') {
    return false;
  }

  const name = getName();

  if (name === 'test') {
    this.setName('');
    return false;
  }

  return name;
}

bad 코드를 살펴보면 함수 내부 최상단에 선언되어 있는데 name을 쓰는 코드는 2번째 if문부터이다.

사실 이 부분은 정말 궁금했던 부분이였는데 여기서 시원하게 정리해주셨다..!

뭔가 더 예뻐보이는 코드로 따지면 const가 위에 선언된 건데, 그러면 그 다음 코드가 만약 그 변수를 필요로 하지 않는다면 저 변수가 최상단에 선언될 필요가 있나..? 불필요한 변수를 선언해서 메모리가 더 드는 건 아닌가..? 하는 딜레마가 있었는데 앞으로는 그런 딜레마에 빠지지 않을 것 같다.
그냥 쓰는 놈 앞에다가 놓자.

변수 할당 체이닝 금지

// bad
(function example() {
  // 자바스크립트는 이것을
  // let a = ( b = ( c = 1 ) );
  // 로 해석합니다.
  // let 키워드는 변수 a에만 적용됩니다.
  // 변수 b와 c는 전역 변수가 됩니다.
  let a = b = c = 1;
}());

console.log(a); // throws ReferenceError
console.log(b); // 1
console.log(c); // 1

// good
(function example() {
  let a = 1;
  let b = a;
  let c = a;
}());

console.log(a); // throws ReferenceError
console.log(b); // throws ReferenceError
console.log(c); // throws ReferenceError

// `const`에도 동일하게 적용됩니다

example 함수를 즉시실행 시키고 있는데,
let a = b = c = 1 이면..
그냥 봤을때는 c가 1 이니까.. b가 1이되고.. 그러면 a도 1이 되겠네? 근데 변수는 블록 스코프니까 바깥에서 콘솔에 출력하면 define 되지 않았다고 하지 않을까? 했는데 b, c는 출력이 되네?

let 키워드 인데? 싶었지만 자바스크립트가 c = 1이렇게 해석한다고 하면 강제적으로 var 로 선언하는 거로 간주하나보다.

자의적으로 생각하면 안되는데 당연히 할당이 재할당되고 재할당되고 바깥에서는 아예 a, b, c 변수를 찾지 못한다고 생각했다.
물론 저렇게 쓸 일도 없겠지만 알아서 나쁠 건 없지..

그럼에도 이부분은 너무 궁금해서 직접 쳐봤다.

b랑 c는 진짜 global로 간주하고 a는 블록 스코프라 에러가 뜨는구나.
오 완전 신기. 근데 내가 쓸 일은 없음.

단항 증감 연산자 ++, -- 사용 금지

보자마자 아니 왜요..???????
진짜 너무 좋아하는 건데....

// bad

const array = [1, 2, 3];
let num = 1;
num++;
--num;

let sum = 0;
let truthyCount = 0;
for (let i = 0; i < array.length; i++) {
  let value = array[i];
  sum += value;
  if (value) {
    truthyCount++;
  }
}

// good

const array = [1, 2, 3];
let num = 1;
num += 1;
num -= 1;

const sum = array.reduce((a, b) => a + b, 0);
const truthyCount = array.filter(Boolean).length;

전위 증감 연산자는 잘 안써도 후위는 많이 썼었는데 권장되지 않는다니!
앞으로 num += 1을 사용해야겠다.

아 물론 알고리즘 문제 풀 때는 못 잃어..
안돼 ++쨩.. 내가 너무 좋아해..

줄바꿈 주의

코드가 길어져서 = 다음의 코드가 줄바꿈 되는 경우 괄호로 감싸주도록하자.

// bad
const foo =
  superLongLongLongLongLongLongLongLongFunctionName();

// bad
const foo
  = 'superLongLongLongLongLongLongLongLongString';

// good
const foo = (
  superLongLongLongLongLongLongLongLongFunctionName()
);

// good
const foo = 'superLongLongLongLongLongLongLongLongString';

사용하지 않는 변수 선언 금지

// bad

var some_unused_var = 42;

// 쓰기 전용 변수는 사용한 것으로 간주되지 않습니다.
var y = 10;
y = 5;

// 자신의 변경을 읽는 것은 사용한 것으로 간주되지 않습니다.
var z = 0;
z = z + 1;

// 사용되지 않은 함수 인자.
function getX(x, y) {
    return x;
}

// good

function getXPlusY(x, y) {
  return x + y;
}

var x = 1;
var y = a + 2;

alert(getXPlusY(x, y));

// 'type'은 사용되지 않을 경우 무시됩니다. 나머지 속성의 형제이기 때문입니다.
// 이것은 특정 키를 생략하는 객체를 추출하는 형식입니다.
var { type, ...coords } = data;
// 'coords'는 이제 'data' 객체에서 'type' 속성이 빠진 'data' 객체입니다.

사용하지 않는 변수를 일부러 선언한 적은 없고 선언해놓고 까먹고 안쓴 적은 많았던 것 같다. ㅎㅎ


참고 자료
Airbnb JavaScript Style Guide

0개의 댓글