forEach
피하기- 매개변수의 숫자 제한
- DOM 이벤트를 처리하기 위해 클래스 피하기
- 생성자에 요소 컨테이너 전달하기
- 문자열을 정수로 변환하기
- CSS 선택자 -
js-
접두어 사용 - ES 모듈 구문
- CommonJS 모듈 구문
- 모듈에 대한 상대 및 절대 경로
- 비페이지 모듈에서
DOMContentLoaded
사용하지 않기 - XSS 피하기
- ESLint
- IIFE(즉시 실행 함수 표현식)
- 전역 네임스페이스
- 부작용
- 순수 함수와 데이터 변이
- 상수를 기본형으로 내보내기
- 에러 처리
JavaScript 스타일 가이드
우리는 에어비앤비 JavaScript 스타일 가이드와 그에 딸린 린터를 사용하여 대부분의 JavaScript 스타일 가이드를 관리합니다.
에어비앤비에서 설정한 스타일 가이드 외에도 몇 가지 특정 규칙이 있습니다.
yarn run lint:eslint:all
또는 yarn run lint:eslint $PATH_TO_FILE
명령을 실행하여 ESLint를 로컬에서 실행할 수 있습니다.
forEach
피하기
데이터를 변형할 때 forEach
를 피하십시오. 데이터를 변형할 때는 map
, reduce
, 또는 filter
를 사용하십시오. 함수 내의 변형을 최소화하여 에어비앤비 스타일 가이드와 일치시킵니다.
// bad
users.forEach((user, index) => {
user.id = index;
});
// good
const usersWithId = users.map((user, index) => {
return Object.assign({}, user, { id: index });
});
매개변수의 숫자 제한
함수 또는 메소드의 매개변수가 3개 이상인 경우 대신에 매개변수로 객체를 사용하십시오.
// bad
function a(p1, p2, p3, p4) {
// ...
};
// good
function a({ p1, p2, p3, p4 }) {
// ...
};
DOM 이벤트를 처리하기 위해 클래스 피하기
클래스의 유일한 목적이 DOM 이벤트를 바인딩하고 콜백을 처리하는 것이라면 함수를 사용하십시오.
// bad
class myClass {
constructor(config) {
this.config = config;
}
init() {
document.addEventListener('click', () => {});
}
}
// good
const myFunction = () => {
document.addEventListener('click', () => {
// 콜백 처리
});
}
생성자에 요소 컨테이너 전달하기
클래스가 DOM을 조작하는 경우 요소 컨테이너를 매개변수로 받으십시오. 이것이 유지보수하기에 더 좋고 성능적으로 유리합니다.
// bad
class a {
constructor() {
document.querySelector('.b');
}
}
// good
class a {
constructor(options) {
options.container.querySelector('.b');
}
}
문자열을 정수로 변환하기
문자열을 정수로 변환할 때 Number
가 의미론적이고 더 가독성이 있습니다. 둘 다 허용되지만 Number
가 약간의 유지보수적 이점이 있습니다.
경고: parseInt
은 기수 인자를 포함해야 합니다.
// bad (기수 인자 누락)
parseInt('10');
// good
parseInt("106", 10);
// good
Number("106");
// bad (기수 인자 누락)
things.map(parseInt);
// good
things.map(Number);
parseInt
를 사용하지 마십시오. 대신 Number
또는 parseFloat
를 고려하십시오.CSS 선택자 - js-
접두어 사용
CSS 클래스가 JavaScript에서 요소를 참조하는 경우 클래스 이름에 js-
접두어를 붙이십시오.
// bad
<button class="add-user"></button>
// good
<button class="js-add-user"></button>
ES 모듈 구문
대부분의 JavaScript 파일에서는 ES 모듈 구문을 사용하여 모듈을 가져오거나 내보냅니다. 이름있는 내보내기를 선호합니다. 이름 일관성을 개선하기 때문입니다.
// bad (예외가 있는 경우, 아래 참조)
export default SomeClass;
import SomeClass from 'file';
// good
export { SomeClass };
import { SomeClass } from 'file';
기본 내보내기는 몇 가지 특정한 상황에서 허용됩니다:
- Vue 단일 파일 컴포넌트 (SFC)
- Vuex 변이 파일
더 많은 정보는 RFC 20를 참조하십시오.
CommonJS 모듈 구문
우리의 Node 구성은 CommonJS 모듈 구문을 요구합니다. 이름 있는 내보내기를 선호합니다.
// bad
module.exports = SomeClass;
const SomeClass = require('./some_class');
// good
module.exports = { SomeClass };
const { SomeClass } = require('./some_class');
모듈에 대한 상대 및 절대 경로
가져오는 모듈이 두 단계 이하인 경우 상대 경로를 사용하십시오.
// bad
import GitLabStyleGuide from '~/guides/GitLabStyleGuide';
// good
import GitLabStyleGuide from '../GitLabStyleGuide';
가져오는 모듈이 두 단계 이상인 경우 절대 경로를 대신 사용하십시오:
// bad
import GitLabStyleGuide from '../../../guides/GitLabStyleGuide';
// good
import GitLabStyleGuide from '~/GitLabStyleGuide';
또한, 전역 네임스페이스에 추가하지 마십시오.
비페이지 모듈에서 DOMContentLoaded
사용하지 않기
가져온 모듈은 로드될 때마다 동일하게 작동해야 합니다. DOMContentLoaded
이벤트는 웹팩에서 동적으로 로드되는 /pages/*
디렉터리에 있는 모듈에서만 허용됩니다.
XSS 피하기
콘텐츠를 설정하기 위해 innerHTML
, append()
또는 html()
을 사용하지 마십시오. 이것은 너무 많은 취약점을 열어 둘 수 있습니다.
ESLint
ESLint 동작 방식은 도구 가이드에서 찾을 수 있습니다.
IIFE(즉시 실행 함수 표현식)
IIFE(즉시 실행 함수 표현식)를 사용하지 마십시오. 많은 파일이 IIFE로 그 내용을 래핑하고 있지만, 이것은 Sprockets에서 웹팩으로 전환한 후에는 더는 필요하지 않습니다. 더 이상 사용하지 마십시오. 레거시 코드를 리팩토링할 때 제거해도 괜찮습니다.
전역 네임스페이스
전역 네임스페이스에 추가하지 마십시오.
// bad
window.MyClass = class { /* ... */ };
// good
export default class MyClass { /* ... */ }
부작용
최상위 부작용
export
를 포함하는 모든 스크립트에서 최상위 부작용을 금지합니다:
// bad
export default class MyClass { /* ... */ }
document.addEventListener("DOMContentLoaded", function(event) {
new MyClass();
}
생성자에서 부작용 피하기
constructor
에서 비동기 호출, API 요청 또는 DOM 조작을 피하십시오. 대신 별도의 함수로 이동하십시오. 이렇게 하면 테스트를 쉽게 작성할 수 있고 단일 책임 원칙을 위반하는 것을 피할 수 있습니다.
// bad
class myClass {
constructor(config) {
this.config = config;
axios.get(this.config.endpoint)
}
}
// good
class myClass {
constructor(config) {
this.config = config;
}
makeRequest() {
axios.get(this.config.endpoint)
}
}
const instance = new myClass();
instance.makeRequest();
순수 함수와 데이터 변이
많은 작은 순수 함수를 작성하고 변이가 발생하는 곳을 최소화하는 데 노력하세요.
// 나쁨
const values = {foo: 1};
function impureFunction(items) {
const bar = 1;
items.foo = items.a * bar + 2;
return items.a;
}
const c = impureFunction(values);
// 좋음
var values = {foo: 1};
function pureFunction (foo) {
var bar = 1;
foo = foo * bar + 2;
return foo;
}
var c = pureFunction(values.foo);
상수를 기본형으로 내보내기
객체를 내보내는 대신 공통 네임스페이스로 상수 기본형을 내보내는 것을 선호합니다. 이는 컴파일 시 참조 검사를 개선하고 런타임에서의 실수로 인한 undefined
를 방지하는 데 도움이 됩니다. 또한 번들 크기를 줄이는 데도 도움이 됩니다.
상수를 컬렉션(배열 또는 객체)로 내보내는 것은 필요에 따라 반복해야할 때에만 수행하세요. 예를 들어 프롭 유효성 검사를 위해 반복해야 할 때입니다.
// 나쁨
export const VARIANT = {
WARNING: 'warning',
ERROR: 'error',
};
// 좋음
export const VARIANT_WARNING = 'warning';
export const VARIANT_ERROR = 'error';
// 필요한 경우 좋음
export const VARIANTS = [VARIANT_WARNING, VARIANT_ERROR];
에러 처리
서버가 500
을 돌려줄 때 내부 서버 오류에 대해 일반적인 에러 메시지를 반환해야 합니다.
백엔드가 오류를 반환할 때, 해당 오류는 사용자에게 표시할 수 있어야 합니다.
만약 어떤 이유로 인해 그것이 어렵다면, 마지막 수단으로 접두어를 붙인 특정한 에러 메시지를 선택할 수 있습니다:
-
백엔드에서 표시할 에러 메시지에 접두어를 붙이도록 확인하세요:
Gitlab::Utils::ErrorMessage.to_user_facing('예시 사용자용 에러 메시지')
-
app/assets/javascripts/lib/utils/error_message.js
에 포함된 에러 메시지 유틸리티 함수를 사용하세요.
이 유틸리티는 두 개의 매개변수를 받습니다. 서버 응답으로 받은 오류 개체 및 기본 오류 메시지입니다. 이 유틸리티는 오류 개체의 메시지를 분석하여 메시지가 사용자에게 표시될 것인지 여부를 나타내는 접두사를 확인합니다. 메시지가 사용자에게 표시될 목적이라면 해당 유틸리티에서 그대로 반환합니다. 그렇지 않으면 매개변수로 전달된 기본 오류 메시지를 반환합니다.
import { parseErrorMessage } from '~/lib/utils/error_message';
onError(error) {
const errorMessage = parseErrorMessage(error, genericErrorText);
}
이 접두어는 API 응답에 사용해서는 안 됩니다. 대신 REST API나 GraphQL 가이드에서 오류 개체를 사용하는 방법을 따르세요.