[JS] Airbnb 컨벤션 정리

홍범선·2023년 10월 19일
0

자바스크립트

목록 보기
2/4

개요

우아한테크코스 프리코스 과제를 하면서 '자바스크립트 컨벤션'을 지키면서 과제를 수행하라고 명시되어 있었다.

'자바스크립트 컨벤션'에 대해서 공부해 볼 필요가 있었다.

자바스크립트 컨벤션 정리

타입

원시형과 참조형에 대해 알아야 한다.

  • 원시형은 string, number, boolean, null 등 원시형에 접근하면 값을 직접 조작한다.
  • 참조형 object, array, function 등 참조형에 접근하면 참조를 통해 값을 조작한다.

=> 원시형 같은 경우 메모리 상에서 스택에 저장된다. 반면에 참조형 같은 경우 메모리 상에서 힙에 저장된다.

const arr = [1,2,3];
const copy_arr = arr;

copy_arr[0] = 5 // arr[0] = 5

이렇게 참조형을 복사할 때에는 깊은 복사를 해야 하는 것이 생각난다.

var보단 let보단 const

  • 모든 참조에는 var대신 const를 사용한다.
    => 참조를 재할당 할 수 없게 함으로써 버그로 이어지는 코드를 방지한다.
// bad
var a = 1;
var b = 2;

// good
const a = 1;
const b = 2;
  • 만약 참조를 재할당 해야 한다면 var 대신 let을 사용한다.
// bad
var count = 1;
if (true) {
  count += 1;
}

// good, use the let.
let count = 1;
if (true) {
  count += 1;
}
  • let 과 const 는 둘 다 블록스코프라는 것을 유의하세요.
// const와 let은 선언된 블록 안에서만 존재합니다.
{
  let a = 1;
  const b = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError
  • var는 함수스코프라는 것이다.

호이스팅

한 때 호이스팅에 대해서 공부한 적이 있었다.
호이스팅이란 코드가 실행되기 전에 선언된 변수와 함수를 기억해 둔다.
코드가 실행되면서 기억해 둔 변수와 함수를 꺼내서 쓰는 구조이다.
즉 안에 있는 변수들을 범위의 최 상단으로 끌어올리는 것이다.

console.log(a) // undefined
var a = 1;
console.log(a) // 1

다른 언어라면 에러가 발생되지만 자바스크립트에서는 호이스팅때문에 에러가 발생하지 않고 undefined가 뜨게 된다.
즉 변수를 멋대로 선언하고 할당도 undefined로 멋대로 한다.

var는 지역변수와 전역변수도 제대로 구분되어 있지 않다.

for(var i = 1; i< 5; i++){
  console.log(i) => 1,2,3,4
}
console.log(i) => 5

var는 함수만 지역변수로 호이스팅이 되고 나머지로 다 전역변수로 올려버린다.
let도 호이스팅이 되지만 할당이 되기 전까지는 TDZ이기 때문에 접근할 수 없다는 에러가 뜬다.
=> 그냥 var를 사용하지 말자

객체

객체를 생성할 때는 리터럴 문법을 사용하자

// bad
const item = new Object();

// good
const item = {};
  • 객체에서 키를 예약어로 이용하지 말자
// bad
const superman = {
  default: { clark: 'kent' },
  private: true,
};

// good
const superman = {
  defaults: { clark: 'kent' },
  hidden: true,
};

예약어는 abstract, break, catch, class, default, private 등이 있다.
자세한 것은 https://redk.tistory.com/7 를 참조하자

프로퍼티의 단축구문은 오브젝트 선언의 시작부분에 그룹화 하자

const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
  episodeOne: 1,
  twoJediWalkIntoACantina: 2,
  lukeSkywalker,
  episodeThree: 3,
  mayTheFourth: 4,
  anakinSkywalker,
};

// good
const obj = {
  lukeSkywalker,
  anakinSkywalker,
  episodeOne: 1,
  twoJediWalkIntoACantina: 2,
  episodeThree: 3,
  mayTheFourth: 4,
};

객체에 값을 추가할 때 'key' : 'value'형태로만 가능할 줄 알았는데

const a = '1'
const b= '2'
const obj = {
  a,
  b,
  test1 : 1,
  test2 : 2
}

이런식으로도 추가 가능하다. 이럴 때 a,b는 앞에 써주자

배열

배열을 작성할 때는 리터럴 구문을 사용하자

// bad
const items = new Array();

// good
const items = [];

리터럴 구문을 사용하면 가독성, 편의성, 또한 배열의 크기와 요소를 직접 정의할 수 있어 성능측면에서도 향상된다고 하니 객체나 배열을 생성할 땐 리터럴 구문을 사용하자

배열을 복사할 때는 배열의 확장 연산자 ...를 이용하자

// bad
const len = items.length;
const itemsCopy = [];
let i;

for (i = 0; i < len; i++) {
  itemsCopy[i] = items[i];
}

// good
const itemsCopy = [...items];

... 연산자를 사용하면 원본 배열을 변경하지 않고 새로운 배열을 만드는 간단한 방법이다.

하나의 오브젝트에서 복수의 프로퍼티를 억세스 할 때는 오브젝트 구조화대입을 이용하자

// bad
function getFullName(user) {
  const firstName = user.firstName;
  const lastName = user.lastName;

  return `${firstName} ${lastName}`;
}

// good
function getFullName(obj) {
  const { firstName, lastName } = obj;
  return `${firstName} ${lastName}`;
}

// best
function getFullName({ firstName, lastName }) {
  return `${firstName} ${lastName}`;
}

리액트를 공부할 때 API에서 객체를 전달받을 때 구조화대입을 사용한 것이 기억난다. 그냥 사용했지만 이제는 알고 사용해야 겠다.

router.post("/bbsListCount", (req, res) => {
    getConnection((conn) => {
        const {userID, curtab, option, input,limit, page, orderTarget, orderValue } = req.body;

이런식으로 말이다.

배열도 마찬가지로 구조화 대입을 이용하자

const arr = [1, 2, 3, 4];

// bad
const first = arr[0];
const second = arr[1];

// good
const [first, second] = arr;

배열도 구조화대입이 되는지 몰랐다.
만약 first, third를 얻고 싶다면

const [first, , third] = arr;

하면 된다.
하지만 순서에 영향을 받기 때문에 오브젝트의 구조화대입을 이용하자.

// bad
function processInput(input) {
  // then a miracle occurs
  // 그리고 기적이 일어납니다.
  return [left, right, top, bottom];
}

// the caller needs to think about the order of return data
// 호출처에서 반환된 데이터의 순서를 고려할 필요가 있습니다.
const [left, __, top] = processInput(input);

// good
function processInput(input) {
  // then a miracle occurs
  // 그리고 기적이 일어납니다.
  return { left, right, top, bottom };
}

// the caller selects only the data they need
// 호출처에서는 필요한 데이터만 선택하면 됩니다.
const { left, right } = processInput(input);

문자열

문자열에는 작은따옴표를 사용하자

// bad
const name = "Capt. Janeway";

// good
const name = 'Capt. Janeway';

문자열을 연결 할 때 템플릿 스트링을 사용하자

// bad
function sayHi(name) {
  return 'How are you, ' + name + '?';
}

// bad
function sayHi(name) {
  return ['How are you, ', name, '?'].join();
}

// good
function sayHi(name) {
  return `How are you, ${name}?`;
}

함수

함수식 보다 함수선언을 이용하자

// bad
const foo = function () {
};

// good
function foo() {
}
console.log(foo()) 

호이스팅과 관련되어 있다. 함수 선언식은 호이스팅시 전체가 올라가는데 함수식, 화살표 함수는 참조만 올라간다. 그래서 함수선언식 같은 경우 선언전에도 사용가능하지만 함수식, 화살표 함수는 함수호출 전에 변수를 선언해야 한다.
안전성 측면에서는 한수식이 더 괜찮아 보이지만 가독성, 편리성 측면에서는 함수선언이 좋아 보인다.

클래스

prototype을 피하고 class를 사용하자

// bad
function Queue(contents = []) {
  this._queue = [...contents];
}
Queue.prototype.pop = function() {
  const value = this._queue[0];
  this._queue.splice(0, 1);
  return value;
}

// good
class Queue {
  constructor(contents = []) {
    this._queue = [...contents];
  }
  pop() {
    const value = this._queue[0];
    this._queue.splice(0, 1);
    return value;
  }
}

상속은 extends를 사용하자

// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
  Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function() {
  return this._queue[0];
}

// good
class PeekableQueue extends Queue {
  peek() {
    return this._queue[0];
  }
}

모듈

import/export를 사용하자

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

주로 COMMONJS방식으로 import, export하였는데, 가이드에서는 ES6문법으로 import, export를 권장하고 있었다.

와일드 카드로 import하지말고 필요한 것만 import하자

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

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

프로퍼티

프로퍼티에 접근할 때에는 .을 사용하자

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

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

// good
const isJedi = luke.jedi;

변수에 접근할 때에는 대괄호[]를 사용하자

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

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

const isJedi = getProp('jedi');

따로 구분없이 사용하였는데 직접 접근할 때에는 .을
변수를 통해 접근할 때에는 []를 사용하는 것이 더 좋아 보인다.

변수

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;

호이스팅

문제 1

function example() {
  console.log(notDefined); // => throws a ReferenceError
}

notDefined가 선언된 것이 없어 에러가 발생한다.

문제 2

function example() {
  console.log(declaredButNotAssigned); // => undefined
  var declaredButNotAssigned = true;
}

호이스팅 된 상태에서 동작한다. 그래서 undefined를 출력한다.

문제 2

function example() {
  let declaredButNotAssigned;
  console.log(declaredButNotAssigned); // => undefined
  declaredButNotAssigned = true;
}

호이스팅이 되지만 변수가 선언된 후 호출했으므로 undefined

문제 3

function example() {
  console.log(declaredButNotAssigned); // => throws a ReferenceError
  console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
  const declaredButNotAssigned = true;
}

호이스팅이 되지만 아직 변수가 선언되기 전에 호출했으므로 오류가 발생

문제 4

function example() {
  console.log(anonymous); // => undefined

  anonymous(); // => TypeError anonymous is not a function

  var anonymous = function() {
    console.log('anonymous function expression');
  };
}

함수식도 마찬가지로 변수가 호이스팅되어 undefined가 발생한다. 하지만 함수식은 함수선언식과 반대로 함수가 할당되기전에 호출되면 에러가 발생한다.

문제 5

function example() {
  console.log(named); // => undefined

  named(); // => TypeError named is not a function

  superPower(); // => ReferenceError superPower is not defined

  var named = function superPower() {
    console.log('Flying');
  };
}

마찬가지로 named가 호이스팅 되어 undefined가 출력된다. 함수식이므로 에러가 발생한다.
함수명이나 함수본체는 호이스팅이 되지 않아 에러가 발생한다.

문제 6

function example() {
  console.log(superPower); // => func

  superPower(); // => Flying

 function superPower() {
    console.log('Flying');
  };
}

함수선언식 같은 경우 에러가 발생하지 않는다. 함수식과 함수선언식 차이를 알아야 할 필요가 있다.

단축형

조건문에서 단축형을 사용하자

// bad
if (name !== '') {
  // ...stuff...
}

// good
if (name) {
  // ...stuff...
}

// bad
if (collection.length > 0) {
  // ...stuff...
}

// good
if (collection.length) {
  // ...stuff...
}

공백

문의 앞과 블록의 뒤에는 빈행을 남겨 주십시오.

// bad
if (foo) {
  return bar;
}
return baz;

// good
if (foo) {
  return bar;
}

return baz;

// bad
const obj = {
  foo() {
  },
  bar() {
  },
};
return obj;

// good
const obj = {
  foo() {
  },

  bar() {
  },
};

return obj;

// bad
const arr = [
  function foo() {
  },
  function bar() {
  },
];
return arr;

// good
const arr = [
  function foo() {
  },

  function bar() {
  },
];

return arr;

쉽게말해 중괄호 후 개행을 해주면 될 것 같다.

소괄호 안쪽에 스페이스를 추가하지 말자

// bad
function bar( foo ) {
  return foo;
}

// good
function bar(foo) {
  return foo;
}

// bad
if ( foo ) {
  console.log(foo);
}

// good
if (foo) {
  console.log(foo);
}

대괄호 안쪽에 스페이스를 추가하지 말자

// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);

// good
const foo = [1, 2, 3];
console.log(foo[0]);

중괄호({})의 안쪽에 스페이스를 추가해 주십시오.

// bad
const foo = {clark: 'kent'};

// good
const foo = { clark: 'kent' };

객체를 선언할 때에는 소괄호, 대괄호와는 반대로 공백을 추가하자
아마 블록과 구별하기 위해서 공백을 넣지 않을까 라는 추측을 해본다.

콤마

끝의 콤마를 하자

// bad
const story = [
    once
  , upon
  , aTime
];

// good
const story = [
  once,
  upon,
  aTime,
];

세미클론

세미클론을 하자

// bad
(function() {
  const name = 'Skywalker'
  return name
})()

// good
(() => {
  const name = 'Skywalker';
  return name;
})();

// good (guards against the function becoming an argument when two files with IIFEs are concatenated)
// good (즉시함수가 연결된 2개의 파일일때 인수가 되는 부분을 보호합니다.
;(() => {
  const name = 'Skywalker';
  return name;
})();

형변환

강제 형변환을 하자

const inputValue = '4';

// bad
const val = new Number(inputValue);

// bad
const val = +inputValue;

// bad
const val = inputValue >> 0;

// bad
const val = parseInt(inputValue);

// good
const val = Number(inputValue);

// good
const val = parseInt(inputValue, 10);
profile
알고리즘 정리 블로그입니다.

0개의 댓글