oris9

[Javascript] 코딩컨벤션 지키면서 코드 짜기 (에어비앤비 코딩 컨벤션) 본문

JavaScript

[Javascript] 코딩컨벤션 지키면서 코드 짜기 (에어비앤비 코딩 컨벤션)

oris9 2024. 4. 10. 20:25

컨벤션을 지키면서 코드를 짜자!!!!!!!!!!!!!!!
코드리뷰에서 C언어의 나쁜 습관이 보인다고 하셨다
아무래도 코딩테스트 공부하면서 다른 분들의 풀이를 참고하다보니 그런 습관이 베인 것 같다 
왜냐면 난 씨언어 모르니깐!!

모르는.거. 한가득 🥵🥵🥵🥵🥵🤢 지킬거. 한가득 ㅎㅎ 🤩 빠이팅 ! 
읽는 사람이 읽기 편하게 유지보수하기 편하게 작성하자 아자자

(원어)https://github.com/airbnb/javascript?tab=readme-ov-file

(한국어)https://github.com/ParkSB/javascript-style-guide

 

 

 

4.6Array.from 반복 가능한 매핑에 스프레드 대신 사용하세요 .... 중간 배열 생성을 방지하기 때문입니다.

// bad
const baz = [...foo].map(bar);

// good
const baz = Array.from(foo, bar);



4.7

// bad
inbox.filter((msg) => {
  const { subject, author } = msg;
  if (subject === 'Mockingbird') {
    return author === 'Harper Lee';
  } else {
    return false;
  }
});

// good
inbox.filter((msg) => {
  const { subject, author } = msg;
  if (subject === 'Mockingbird') {
    return author === 'Harper Lee';
  }

  return false;
});

4.8 배열에 여러 줄이 있는 경우 배열 괄호를 연 후, 배열 괄호를 닫기 전에 줄 바꿈을 사용하세요.

// bad
const arr = [
  [0, 1], [2, 3], [4, 5],
];

const objectInArray = [{
  id: 1,
}, {
  id: 2,
}];

const numberInArray = [
  1, 2,
];

// good
const arr = [[0, 1], [2, 3], [4, 5]];

const objectInArray = [
  {
    id: 1,
  },
  {
    id: 2,
  },
];

const numberInArray = [
  1,
  2,
];

 

5.1 객체의 여러 속성에 접근하고 사용할 때 객체 구조 분해를 사용하세요. 에스린트:prefer-destructuring

왜? 구조 분해를 사용하면 해당 속성에 대한 임시 참조를 생성하고 객체에 반복적으로 액세스할 필요가 없습니다. 객체 액세스를 반복하면 코드가 더 반복적으로 생성되고, 더 많은 읽기가 필요하며, 실수할 가능성이 더 커집니다. 또한 객체 구조 분해는 사용되는 항목을 결정하기 위해 전체 블록을 읽어야 하는 대신 블록에 사용되는 객체 구조 정의의 단일 사이트를 제공합니다.

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

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

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

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

 

5.3 여러 반환 값에는 배열 구조 분해가 아닌 객체 구조 분해를 사용하세요.

왜? 시간이 지남에 따라 새 속성을 추가하거나 호출 사이트를 중단하지 않고 사물의 순서를 변경할 수 있습니다.

// 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, top } = processInput(input);

6.1'' 문자열에는 작은따옴표를 사용하세요 . 에스린트:quotes

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

// bad - template literals should contain interpolation or newlines
const name = `Capt. Janeway`;

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

6.2 한 줄이 100자를 초과하게 만드는 문자열은 문자열 연결을 사용하여 여러 줄에 걸쳐 작성해서는 안 됩니다.

왜? 끊어진 문자열은 작업하기 힘들고 코드 검색도 어렵게 만듭니다.

// bad
const errorMessage = 'This is a super long error that was thrown because \
of Batman. When you stop to think about how Batman had anything to do \
with this, you would get nowhere \
fast.';

// bad
const errorMessage = 'This is a super long error that was thrown because ' +
  'of Batman. When you stop to think about how Batman had anything to do ' +
  'with this, you would get nowhere fast.';

// good
const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

6.4eval() 문자열에는 절대 사용하지 마세요 . 너무 많은 취약점을 열어줍니다. 에스린트:no-eval

6.5 문자열에서 문자를 불필요하게 이스케이프 처리하지 마세요. 에스린트:no-useless-escape

왜? 백슬래시는 가독성을 저하시키므로 필요한 경우에만 사용되어야 합니다.

// bad
const foo = '\'this\' \i\s \"quoted\"';

// good
const foo = '\'this\' is "quoted"';
const foo = `my name is '${name}'`;

7.1 함수 선언 대신 명명된 함수 표현식을 사용하세요. 에스린트: func-style,func-names

왜? 함수 선언은 호이스팅됩니다. 즉, 파일에 정의되기 전에 함수를 참조하는 것이 너무 쉽다는 뜻입니다. 이는 가독성과 유지 관리성에 해를 끼칩니다. 함수의 정의가 파일의 나머지 부분을 이해하는 데 방해가 될 만큼 크거나 복잡하다면, 이제 해당 정의를 자체 모듈로 추출해야 할 때입니다! 이름이 포함된 변수에서 유추되는지 여부에 관계없이 표현식의 이름을 명시적으로 지정하는 것을 잊지 마십시오(이는 최신 브라우저나 Babel과 같은 컴파일러를 사용할 때 종종 발생합니다). 이는 오류의 호출 스택에 대한 모든 가정을 제거합니다. ( 논의 )

// bad
function foo() {
  // ...
}

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

// good
// lexical name distinguished from the variable-referenced invocation(s)
const short = function longUniqueMoreDescriptiveLexicalFoo() {
  // ...
};

 

7.2 즉시 호출되는 함수 표현식을 괄호로 묶습니다. 에스린트:wrap-iife

왜? 즉시 호출되는 함수 표현식은 단일 단위입니다. 이를 모두 감싸고 해당 호출 parens를 parens로 묶어 이를 명확하게 표현합니다. 어디에나 모듈이 있는 세상에서는 IIFE가 거의 필요하지 않습니다.

// immediately-invoked function expression (IIFE)
(function () {
  console.log('Welcome to the Internet. Please follow me.');
}());

 

7.3 비함수 블록( if, while등)에서는 함수를 선언하지 마십시오. 대신 함수를 변수에 할당하십시오. 브라우저에서는 이를 허용하지만 모두 다르게 해석하므로 나쁜 소식입니다. 에스린트:no-loop-func

 

7.4 참고: ECMA-262는 a를 block문의 목록으로 정의합니다. 함수 선언은 명령문이 아닙니다.

// bad
if (currentUser) {
  function test() {
    console.log('Nope.');
  }
}

// good
let test;
if (currentUser) {
  test = () => {
    console.log('Yup.');
  };
}

 

7.5 매개변수 이름을 지정하지 마십시오 arguments. 이는 arguments모든 함수 범위에 제공되는 객체 보다 우선합니다 .

// bad
function foo(name, options, arguments) {
  // ...
}

// good
function foo(name, options, args) {
  // ...
}

 

7.6 절대 사용하지 마세요 arguments. 대신에 나머지 구문을 사용하세요 .... 에스린트:prefer-rest-params

왜? ...어떤 인수를 가져오려는지에 대해 명시적입니다. 게다가 나머지 인수는 실제 배열이며 단순히 배열과 유사한 arguments.

// bad
function concatenateAll() {
  const args = Array.prototype.slice.call(arguments);
  return args.join('');
}

// good
function concatenateAll(...args) {
  return args.join('');
}

 

7.7 함수 인수를 변경하는 대신 기본 매개변수 구문을 사용하세요.

// really bad
function handleThings(opts) {
  // No! We shouldn’t mutate function arguments.
  // Double bad: if opts is falsy it'll be set to an object which may
  // be what you want but it can introduce subtle bugs.
  opts = opts || {};
  // ...
}

// still bad
function handleThings(opts) {
  if (opts === void 0) {
    opts = {};
  }
  // ...
}

// good
function handleThings(opts = {}) {
  // ...
}

7.8 기본 매개변수로 부작용을 피하세요.

왜? 그들은 추론하기가 혼란스럽습니다.

let b = 1;
// bad
function count(a = b++) {
  console.log(a);
}
count();  // 1
count();  // 2
count(3); // 3
count();  // 3

 

7.9 항상 기본 매개변수를 마지막에 두십시오. 에스린트:default-param-last

// bad
function handleThings(opts = {}, name) {
  // ...
}

// good
function handleThings(name, opts = {}) {
  // ...
}

7.10 새로운 함수를 생성하기 위해 Function 생성자를 사용하지 마세요. 에스린트:no-new-func

왜? 이런 방식으로 함수를 생성하면 eval()취약점이 열리는 와 유사하게 문자열을 평가합니다 .

// bad
const add = new Function('a', 'b', 'return a + b');

// still bad
const subtract = Function('a', 'b', 'return a - b');

 

7.12 매개변수를 변경하지 마세요. 에스린트:no-param-reassign

왜? 매개변수로 전달된 객체를 조작하면 원래 호출자에게 원치 않는 다양한 부작용이 발생할 수 있습니다.

// bad
function f1(obj) {
  obj.key = 1;
}

// good
function f2(obj) {
  const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
}

 

7.13 절대 매개변수를 재할당하지 마세요. 에스린트:no-param-reassign

왜? 매개변수를 재할당하면 특히 개체에 액세스할 때 예기치 않은 동작이 발생할 수 있습니다 arguments. 특히 V8에서는 최적화 문제가 발생할 수도 있습니다.

// bad
function f1(a) {
  a = 1;
  // ...
}

function f2(a) {
  if (!a) { a = 1; }
  // ...
}

// good
function f3(a) {
  const b = a || 1;
  // ...
}

function f4(a = 1) {
  // ...
}

 

7.14... 가변 함수를 호출하려면 스프레드 구문을 사용하는 것이 좋습니다 . 에스린트:prefer-spread

왜? 더 깨끗하고 컨텍스트를 제공할 필요 가 없으며 new.apply

// bad
const x = [1, 2, 3, 4, 5];
console.log.apply(console, x);

// good
const x = [1, 2, 3, 4, 5];
console.log(...x);

// bad
new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));

// good
new Date(...[2016, 8, 5]);

 

8.1 인라인 콜백을 전달할 때와 같이 익명 함수를 사용해야 하는 경우 화살표 함수 표기법을 사용하세요. 에스린트: prefer-arrow-callback,arrow-spacing

왜? this이는 일반적으로 원하는 것이며 보다 간결한 구문인 의 컨텍스트에서 실행되는 함수 버전을 생성합니다 .

왜 안 돼? 상당히 복잡한 함수가 있는 경우 해당 논리를 자체 명명된 함수 표현식으로 이동할 수 있습니다.

// bad
[1, 2, 3].map(function (x) {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map((x) => {
  const y = x + 1;
  return x * y;
});

 

???

8.2 함수 본문이 부작용 없이 표현식을 반환하는 단일 문으로 구성된 경우 중괄호를 생략하고 암시적 반환을 사용하세요. 그렇지 않으면 중괄호를 유지하고 return명령문을 사용하십시오. 에스린트: arrow-parens,arrow-body-style

왜? 구문 설탕. 여러 기능이 함께 연결되어 있으면 잘 읽혀집니다.

 

8.3 표현식이 여러 줄에 걸쳐 있는 경우 가독성을 높이기 위해 괄호로 묶습니다.

왜? 함수가 시작하고 끝나는 위치를 명확하게 보여줍니다.

// bad
['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call(
    httpMagicObjectWithAVeryLongName,
    httpMethod,
  )
);

// good
['get', 'post', 'put'].map((httpMethod) => (
  Object.prototype.hasOwnProperty.call(
    httpMagicObjectWithAVeryLongName,
    httpMethod,
  )
));

 

8.4 명확성과 일관성을 위해 주장 주위에는 항상 괄호를 포함하십시오. 에스린트:arrow-parens

왜? 인수를 추가하거나 제거할 때 차이 변동을 최소화합니다

// bad
[1, 2, 3].map(x => x * x);

// good
[1, 2, 3].map((x) => x * x);

// bad
[1, 2, 3].map(number => (
  `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));

// good
[1, 2, 3].map((number) => (
  `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));

// bad
[1, 2, 3].map(x => {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map((x) => {
  const y = x + 1;
  return x * y;
});

8.6 암시적 반환을 사용하여 화살표 함수 본문의 위치를 ​​강제합니다. 에스린트:implicit-arrow-linebreak

// bad
(foo) =>
  bar;

(foo) =>
  (bar);

// good
(foo) => bar;
(foo) => (bar);
(foo) => (
   bar
)

9.1 항상 를 사용하세요 class. 직접 조작하는 것을 피하세요 prototype

9.2 상속에 사용합니다 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];
  }
}

??

9.3this 메소드는 메소드 체이닝에 도움을 주기 위해 돌아올 수 있습니다 .

// bad
Jedi.prototype.jump = function () {
  this.jumping = true;
  return true;
};

Jedi.prototype.setHeight = function (height) {
  this.height = height;
};

const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined

// good
class Jedi {
  jump() {
    this.jumping = true;
    return this;
  }

  setHeight(height) {
    this.height = height;
    return this;
  }
}

const luke = new Jedi();

luke.jump()
  .setHeight(20);

 

9.4 사용자 정의 메소드를 작성하는 것은 괜찮습니다 toString(). 단지 그것이 성공적으로 작동하고 부작용이 없는지 확인하십시오.

class Jedi {
  constructor(options = {}) {
    this.name = options.name || 'no name';
  }

  getName() {
    return this.name;
  }

  toString() {
    return `Jedi - ${this.getName()}`;
  }
}

 

9.5 클래스는 지정되지 않은 경우 기본 생성자를 갖습니다. 빈 생성자 함수나 부모 클래스에 위임하는 함수는 필요하지 않습니다. 에스린트:no-useless-constructor

// bad
class Jedi {
  constructor() {}

  getName() {
    return this.name;
  }
}

// bad
class Rey extends Jedi {
  constructor(...args) {
    super(...args);
  }
}

// good
class Rey extends Jedi {
  constructor(...args) {
    super(...args);
    this.name = 'Rey';
  }
}

9.7this 외부 라이브러리나 프레임워크에서 특정 비정적 메서드 사용을 요구하지 않는 한 클래스 메서드는 정적 메서드를 사용하거나 정적 메서드로 만들어야 합니다 . 인스턴스 메서드라는 것은 수신자의 속성에 따라 다르게 동작한다는 것을 나타내야 합니다. 에스린트:class-methods-use-this

// bad
class Foo {
  bar() {
    console.log('bar');
  }
}

// good - this is used
class Foo {
  bar() {
    console.log(this.bar);
  }
}

// good - constructor is exempt
class Foo {
  constructor() {
    // ...
  }
}

// good - static methods aren't expected to use this
class Foo {
  static bar() {
    console.log('bar');
  }
}

 

10.1 항상 비표준 모듈 시스템보다는 모듈( 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;

10.5 변경 가능한 바인딩을 내보내지 마세요. 에스린트:import/no-mutable-exports

왜? 일반적으로 변형은 피해야 하지만, 특히 변경 가능한 바인딩을 내보낼 때 더욱 그렇습니다. 일부 특수한 경우에는 이 기술이 필요할 수 있지만 일반적으로 상수 참조만 내보내야 합니다.

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

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

10.9 모듈 import 문에서 Webpack 로더 구문을 허용하지 않습니다. 에스린트:import/no-webpack-loader-syntax

왜? 가져오기에서 Webpack 구문을 사용하므로 코드가 모듈 번들러에 연결됩니다. NET에서 로더 구문을 사용하는 것이 좋습니다 webpack.config.js.

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

 

10.10 JavaScript 파일 이름 확장자 eslint를 포함하지 마세요:import/extensions

왜? 확장을 포함하면 리팩토링이 금지되고 모든 소비자에게 가져오는 모듈의 구현 세부 정보가 부적절하게 하드코딩됩니다.

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

 

11.1 반복자를 사용하지 마세요. for-in또는 같은 루프 대신 JavaScript의 고차 함수를 선호합니다 for-of. 에스린트:no-iterator no-restricted-syntax

왜? 이는 불변의 규칙을 시행합니다. 값을 반환하는 순수 함수를 다루는 것은 부작용보다 추론하기가 더 쉽습니다.

map()/ every()/ filter()/ find()/ findIndex()/ reduce()/ / ...를 사용 some()하여 배열을 반복하고, Object.keys()/ Object.values()/를 Object.entries()사용하여 객체를 반복할 수 있는 배열을 생성합니다.

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

12.1 속성에 접근할 때 점 표기법을 사용하세요. 에스린트:dot-notation

12.2[] 변수로 속성에 접근할 때 대괄호 표기법을 사용하세요 .

12.3** 지수를 계산할 때 지수 연산자를 사용하세요 . 에스린트: prefer-exponentiation-operator.

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

// good
const binary = 2 ** 10;

13.3 모든 const항목을 그룹화한 다음 모든 let항목을 그룹화합니다.

왜? 이는 나중에 이전에 할당된 변수 중 하나에 따라 변수를 할당해야 할 때 유용합니다.

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

13.4 필요한 곳에 변수를 할당하되 적절한 위치에 배치하세요.

왜? 함수 범위가 아닌 블록 범위입니다 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;
}

 

13.5 변수 할당을 연결하지 마세요. 에스린트:no-multi-assign

왜? 변수 할당을 연결하면 암시적 전역 변수가 생성됩니다.

 

// bad
(function example() {
  // JavaScript interprets this as
  // let a = ( b = ( c = 1 ) );
  // The let keyword only applies to variable a; variables b and c become
  // global variables.
  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

// the same applies for `const`

13.6 단항 증가 및 감소( ++, --) 사용을 피하세요. 에스린트no-plusplus

왜? eslint 문서에 따르면 단항 증가 및 감소 문은 자동 세미콜론 삽입의 대상이 되며 애플리케이션 내에서 값을 증가시키거나 감소시키면서 자동 오류가 발생할 수 있습니다. 또한 num += 1대신에 num++또는 같은 문을 사용하여 값을 변경하는 것이 더 표현력이 좋습니다 num ++. 단항 증가 및 감소 문을 허용하지 않으면 의도치 않게 값을 사전 증가/사전 감소시켜 프로그램에서 예기치 않은 동작을 유발할 수도 있습니다.

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

13.7= 할당 전후에 줄바꿈을 피하세요 . 할당이 위반하는 경우 max-len값을 괄호로 묶습니다. 에스린트 operator-linebreak.

왜? 주변의 줄 바꿈은 =할당 값을 난독화할 수 있습니다.

// bad
const foo =
  superLongLongLongLongLongLongLongLongFunctionName();

// bad
const foo
  = 'superLongLongLongLongLongLongLongLongString';

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

// good
const foo = 'superLongLongLongLongLongLongLongLongString';

 

 

14부터 한번 . 더읽기