forEach
피하기- 매개변수 수 제한
- DOM 이벤트 처리를 위한 클래스 피하기
- 생성자에 요소 컨테이너 전달
- 문자열을 정수로 변환하기
- CSS 선택자 -
js-
접두사 사용 - ES 모듈 구문
- CommonJS 모듈 구문
- 모듈의 절대 경로 vs 상대 경로
- 페이지가 아닌 모듈에서
DOMContentLoaded
를 사용하지 마세요 - XSS 피하기
- ESLint
- IIFE
- 전역 네임스페이스
- 부작용
- 순수 함수 및 데이터 변형
- 상수는 원시값으로 내보내기
- 오류 처리
JavaScript 스타일 가이드
우리는 Airbnb JavaScript 스타일 가이드와 그에 따른 리인터를 사용하여 대부분의 JavaScript 스타일 가이드라인을 관리합니다.
Airbnb에서 설정한 스타일 가이드라인 외에도 아래에 나열된 몇 가지 특정 규칙이 있습니다.
yarn run lint:eslint:all
또는 yarn run lint:eslint $PATH_TO_FILE
를 실행할 수 있습니다.
forEach
피하기
데이터를 변형할 때 forEach
를 피하세요. 데이터 변형시 forEach
대신 map
, reduce
또는 filter
를 사용하세요.
이것은 함수 내에서의 변형을 최소화하며, Airbnb 스타일 가이드와 일치합니다.
// 나쁨
users.forEach((user, index) => {
user.id = index;
});
// 좋음
const usersWithId = users.map((user, index) => {
return Object.assign({}, user, { id: index });
});
매개변수 수 제한
함수나 메서드에 매개변수가 3개를 초과하면, 매개변수로 객체를 사용하세요.
// 나쁨
function a(p1, p2, p3, p4) {
// ...
};
// 좋음
function a({ p1, p2, p3, p4 }) {
// ...
};
DOM 이벤트 처리를 위한 클래스 피하기
클래스의 유일한 목적이 DOM 이벤트를 바인딩하고 콜백을 처리하는 경우, 함수를 사용하는 것을 선호하세요.
// 나쁨
class myClass {
constructor(config) {
this.config = config;
}
init() {
document.addEventListener('click', () => {});
}
}
// 좋음
const myFunction = () => {
document.addEventListener('click', () => {
// 여기서 콜백 처리
});
}
생성자에 요소 컨테이너 전달
클래스가 DOM을 조작할 때, 요소 컨테이너를 매개변수로 받으세요.
이것은 더 유지보수하기 쉽고 성능이 뛰어납니다.
// 나쁨
class a {
constructor() {
document.querySelector('.b');
}
}
// 좋음
class a {
constructor(options) {
options.container.querySelector('.b');
}
}
문자열을 정수로 변환하기
문자열을 정수로 변환할 때, Number
는 의미적이며 읽기 쉬울 수 있습니다. 둘 다 허용되지만, Number
가 조금 더 유지보수에 유리합니다.
경고: parseInt
는 진수 인자를 포함해야 합니다.
// 나쁨 (진수 인자 누락)
parseInt('10');
// 좋음
parseInt("106", 10);
// 좋음
Number("106");
// 나쁨 (진수 인자 누락)
things.map(parseInt);
// 좋음
things.map(Number);
Number
또는 parseFloat
를 고려하세요.CSS 선택자 - js-
접두사 사용
CSS 클래스가 JavaScript에서 요소를 참조하는 목적만 위해 사용되는 경우, 클래스 이름에 js-
를 접두사로 붙이세요.
// 나쁨
<button class="add-user"></button>
// 좋음
<button class="js-add-user"></button>
ES 모듈 구문
대부분의 JavaScript 파일에 대해, ES 모듈 구문을 사용하여 모듈에서 가져오거나 내보내세요. 이름 일관성을 높이기 위해 명명된 내보내기를 선호하세요.
// 나쁨 (예외가 있음, 아래 참조)
export default SomeClass;
import SomeClass from 'file';
// 좋음
export { SomeClass };
import { SomeClass } from 'file';
기본 내보내기를 사용하는 것은 몇 가지 특정 상황에서 허용됩니다:
- Vue 단일 파일 구성 요소(SFCs)
- Vuex 변이 파일
자세한 내용은 RFC 20를 참조하세요.
CommonJS 모듈 구문
우리의 Node 구성은 CommonJS 모듈 구문을 필요로 합니다. 명명된 내보내기를 선호하세요.
// 나쁨
module.exports = SomeClass;
const SomeClass = require('./some_class');
// 좋음
module.exports = { SomeClass };
const { SomeClass } = require('./some_class');
모듈의 절대 경로 vs 상대 경로
모듈을 가져올 때 해당 모듈이 두 레벨 이하일 경우 상대 경로를 사용하세요.
// 나쁨
import GitLabStyleGuide from '~/guides/GitLabStyleGuide';
// 좋음
import GitLabStyleGuide from '../GitLabStyleGuide';
모듈을 가져올 때 해당 모듈이 두 레벨 이상일 경우 절대 경로를 사용하세요:
// 나쁨
import GitLabStyleGuide from '../../../guides/GitLabStyleGuide';
// 좋음
import GitLabStyleGuide from '~/GitLabStyleGuide';
추가로, 전역 네임스페이스에 추가하지 마세요.
페이지가 아닌 모듈에서 DOMContentLoaded
를 사용하지 마세요
가져온 모듈은 매번 로드될 때 동일하게 작동해야 합니다. DOMContentLoaded
이벤트는 /pages/*
디렉토리에 로드된 모듈에서만 허용됩니다.
이 모듈들은 webpack을 사용하여 동적으로 로드되기 때문입니다.
XSS 피하기
innerHTML
, append()
또는 html()
를 사용하여 콘텐츠를 설정하지 마세요. 이러한 방법은 너무 많은 취약점을 열어줍니다.
ESLint
ESLint 동작은 우리의 도구 가이드에서 찾을 수 있습니다.
IIFE
IIFE(즉시 실행 함수 표현식)를 사용하지 마세요. 비록 우리가 IIFE로 내용을 감싸는 파일의 많은 예가 있지만, Sprockets에서 webpack으로 전환한 이후에는 더 이상 필요하지 않습니다. 더 이상 사용하지 마세요. 레거시 코드를 리팩토링할 때 이를 제거해도 괜찮습니다.
전역 네임스페이스
전역 네임스페이스에 추가하는 것을 피하세요.
// 나쁨
window.MyClass = class { /* ... */ };
// 좋음
export default class MyClass { /* ... */ }
부작용
최상위 부작용
export
가 포함된 스크립트에서는 최상위 부작용이 금지됩니다:
// 나쁨
export default class MyClass { /* ... */ }
document.addEventListener("DOMContentLoaded", function(event) {
new MyClass();
}
생성자에서 부작용을 피하세요
constructor
에서 비동기 호출, API 요청 또는 DOM 조작을 하지 마세요.
대신 별도의 함수로 이동하세요. 이는 테스트 작성을 더 쉽게 하고
단일 책임 원칙을 위반하는 것을 피합니다.
// 나쁨
class myClass {
constructor(config) {
this.config = config;
axios.get(this.config.endpoint)
}
}
// 좋음
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
를 피할 수 있습니다. 또한 번들 크기를 줄이는 데 도움이 됩니다.
반복할 필요가 있는 경우(예: prop 검증기)만 상수를 컬렉션(배열 또는 객체)으로 내보내세요.
// 나쁨
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 가이드를 따라 오류 객체를 소비하는 방법을 확인하십시오.