코드컨벤션
#자바스크립트 #중요 #개념
참조
- 모든 참조에는
var대신const를 쓰기 참조를 재할당 할수 없게 함으로써, 버그를 방지
[!black]- 예시
// bad var a = 1; var b = 2; // good const a = 1; const b = 2;
- 참조에 재할당을 해야하는 상황이면
let을 사용
[!black]- 예시
// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }
const,let모두 블록단위 스코프임에 유의
객체
- 객체 생성시 리터럴 문법을 사용
객체 생성시
{}를 사용하라는 뜻
[!black]- 예시
// bad const item = new Object(); / good const item = {};
- 동적 속성을 갖는 객체는 속성 계산명을 사용
속성명이 바뀔수 있는 속성은 속성계산명
[Key]: value을 사용
[!black]- 예시
function getKey(k) { return `a key named ${k}`; } // bad const obj = { id: 5, name: 'San Francisco', }; obj[getKey('enabled')] = true; // good const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true, };
- 메소드의 단축구문을 사용 속성과 값의 이름이 동일하면 속성이름만 적기
[!black]- 예시
// bad const atom = { value: 1, addValue: function (value) { return atom.value + value; }, }; // good const atom = { value: 1, addValue(value) { return atom.value + value; }, };
[!black]- 예시
const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, };
- 단축구문을 사용한경우 객체의 최상단에 배치
- 유효하지 않은 식별자에만 따옴표 속성 사용 일반적인 속성은 따옴표 없이 표기
[!black]- 예시
// bad const bad = { foo: 3, bar: 4, 'data-blah': 5, }; // good const good = { foo: 3, bar: 4, 'data-blah': 5, };
hasOwnProperty,propertyIsEnumerable,isPrototypeOf와 같은Object.prototype메소드를 직접 호출하지 말기 객체의 속성에 의해 메소드가 가려질수 있음-
[!black]- 가려진 예시
const object = { a: 1, hasOwnProperty: false, }; // 이 경우에는 오류가 발생합니다. console.log(object.hasOwnProperty('a')); // TypeError: object.hasOwnProperty is not a function
-
[!black]- 예시
// bad console.log(object.hasOwnProperty(key)); // good console.log(Object.prototype.hasOwnProperty.call(object, key)); // best const has = Object.prototype.hasOwnProperty; // 모듈스코프에서 한 번 캐시하세요. console.log(has.call(object, key)); /* or \*/ import has from 'has'; // https://www.npmjs.com/package/has console.log(has(object, key));
- 객체에 대한 얕은복사를 할 때는
Object.assign대신 객체 전개 구문을 사용 - 특정 속성이 생략된 새로운 개체를 가져올 때는 객체 나머지 연산자 사용 js에선 원본 객체가 손상되는 것을 최대한으로 지양한다
[!black]- 예시
// very bad const original = { a: 1, b: 2 }; const copy = Object.assign(original, { c: 3 }); // `original`을 변조합니다 ಠ_ಠ delete copy.a; // 그래서 이렇게 합니다 // bad const original = { a: 1, b: 2 }; const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 } // good const original = { a: 1, b: 2 }; const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 } const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
배열
- 배열을 생성할떄 리터럴 구문을 사용 리터럴이라는 말이 계속 나오는데 정확한 뜻을 몰라서 찾아봄 JS용어
[!black]- 예시
// bad const items = new Array(); // good const items = [];
- 배열에 직접 값을 할당하지 말고, Array#push 사용
[!black]- 예시
const someStack = []; // bad someStack[someStack.length] = 'abracadabra'; // good someStack.push('abracadabra');
- 순회가능한 객체 (iterable object) 를 배열로 만들 때,
Array.from대신, … 구문을 사용 순회가능 객체가 뭐지? Iterable Object → (Array, String, Set, Map, …)
[!black]- 예시
const foo = document.querySelectorAll('.foo'); // good const nodes = Array.from(foo); // best const nodes = [...foo];
- array-like 객체를 배열로 변환할 때,
Array.from사용 array-like가 뭐지? Array-Like → (length 속성과, 인덱싱(0,1,2,…)된 요소를 가진 객체)
[!black]- 예시
const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 }; // bad const arr = Array.prototype.slice.call(arrLike); // good const arr = Array.from(arrLike);
- 매핑할 때는 전개 구문 … 대신
Array.from을 사용 중간 배열 생성을 방지
[!black]- 예시
// bad const baz = [...foo].map(bar); // good const baz = Array.from(foo, bar);
white
Array.from은 map에 비해 메모리는 적게쓰지만, 오래걸린다는 단점이 있음 StackOverFlow
- 배열 메소드 콜백에는 리턴 구문 사용
[!black]- 예시
// good [1, 2, 3].map((x) => { const y = x + 1; return x * y; }); // good [1, 2, 3].map((x) => x + 1); // bad - no returned value means `acc` becomes undefined after the first iteration [ [0, 1], [2, 3], [4, 5], ].reduce((acc, item, index) => { const flatten = acc.concat(item); acc[index] = flatten; }); // good [ [0, 1], [2, 3], [4, 5], ].reduce((acc, item, index) => { const flatten = acc.concat(item); acc[index] = flatten; return flatten; }); // 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; });
reduce사용할 때, 초기값 설정 안하면 배열의 0번 인덱스를 초기값으록 가진다
- 배열이 여러줄에 걸쳐 있다면 배열을 연 이후와 닫기 이전에 줄바꿈하기
[!black]- 예시
// 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];
비구조화
- 하나의 객체에서 여러 속성에 접근할 때에는 객체 비구조화 사용 속성들을 위한 임시 참조를 만들지 않게 해주고, 객체에 반복적인 접근방지
[!black]- 예시
// 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}`; }
- 배열 비구조화 를 사용
- 여러 값을 반환하는 경우 배열 비구조화 말고, 객체 비구조화 사용 배열 비구조화를 사용하려면 비구조화시 배열의 순서까지 고려해야하는 불편함이 있음
[!black]- 예시
// bad function processInput(input) { // 기적이 일어납니다 return [left, right, top, bottom]; } // 반환되는 데이터의 순서를 생각해야합니다 const [left, __ , top] = processInput(input); // good function processInput(input) { // 기적이 일어납니다 return { left, right, top, bottom }; } // 필요한 데이터만 선택하면 됩니다 const { left, top } = processInput(input);
문자열
- 문자열에는 작은 따옴표 사용
- 100자가 넘는 문자열을 문자열 연결을 이용해 여러줄에 걸쳐 쓰지 말기 문자열이 끊어지면 작업하기 까다롭고, 찾기도 힘듬
[!black]- 에시
// 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.';
- 문자열을 생성하는 경우, 문자열 연결 대신, 템플릿 문자열 사용
[!black]- 예시
// 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}?`; }
-
절대로 문자열에
eval()사용하면 안됨, 너무나 많은 취약점을 만듦 eval is evil -
문자열에 불필요한 이스케이프 문자 사용 자제 가독성을 해침
함수
- 함수선언식 말고 기명 함수표현식을 사용 함수 선언은 호이스팅 된다. 즉 함수가 선언되기 전에 함수를 참조하는것이 쉽다는 뜻 이는 유지보수에 어려움을 가져다 준다, 함수에 이름을 명시적으로 지정하면 디버깅 시 콜 스택에서 함수이름을 알 수 있다
[!black]- 예시
// bad function foo() { // ... } // bad const foo = function () { // ... }; // good // 변수 참조 호출과 구분되는 이름 const short = function longUniqueMoreDescriptiveLexicalFoo() { // ... };
- 즉시 함수 표현식을 괄호로 감싸기 괄호로 감싸면 괄호 안의 표현을 명확하게 해줌
[!black]- 예시
// 즉시 호출 함수 표현식 (IIFE) (function () { console.log('Welcome to the Internet. Please follow me.'); })();
white
즉시 함수 표현식에 방법은 여러 방법이 있지만 전체를 괄호로 묶는 방식을 사용하자 (function() {})() [X] (function() {}()) [O]
-
함수 이외의 블록(If, while, {}, 등)에서 함수를 선언하지 말기, 브라우저는 이를 허용하지만, 모두 다 다르게 해석한다
-
참고 ECMA-262 명세는
블록을 구문으로 명시하고 있지만 함수는 구문이 아님
[!black]- 예시
// bad if (currentUser) { function test() { console.log('Nope.'); } } // good let test; if (currentUser) { test = () => { console.log('Yup.'); }; }
white
표현식: 표현식은 값을 계산하고 반환합니다. 구문: 구문은 특정 작업을 수행하며, 프로그램의 흐름을 제어합니다. 구문과 표현식
-
절대 함수의 매개변수 이름을
arguments로 지으면 안됨 함수 스코프에 전해지는 arguments 객체의 참조를 덮어씀 -
절대
arguments를 사용하지 말기, 차라리 나머지 문법…사용하기 … 을 사용하면 매개변수를 몇개 사용할지 확실히 할수 있고, 나머지 문법을 사용한것은 진짜 Array인것에 반해 arguments는 Array-Like 객체가 아니다
[!black]- 예시
// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
- 함수의 인자를 변조하기 보다는 기본 매개변수 문법을 사용
[!black]- 에시
// really bad function handleThings(opts) { // 안돼요! 우리는 함수 인자를 변경하면 안됩니다. // 더 안 좋은 경우: 만약 opts가 falsy한 값일 경우 당신이 원하는 객체로 // 설정되겠지만, 이는 미묘한 버그를 일으킬 수 있습니다. opts = opts || {}; // ... } // still bad function handleThings(opts) { if (opts === void 0) { opts = {}; } // ... } // good function handleThings(opts = {}) { // ... }
white
void 0 은 undefined 를 뜻한다, void 0 == null: true, void 0 === null: false, void 0 == false: false
- 사이드 이펙트가 있을만한 기본 매개변수는 사용하지 않기 혼란을 야기
[!black]- 에시
var b = 1; // bad function count(a = b++) { console.log(a); } count(); // 1 count(); // 2 count(3); // 3 count(); // 3
white
사이드이펙트(부수효과): 하나의 동작에, 두개 이상의 효과를 가져다 주는 것이라고 이해했다 함수를 실행 → 전체 상태가 변화 (리액트) 함수를 실행 → 외부 변수의 값이 변화 값을 할당 → 다른 값도 변화
사이드 이펙트가 나쁜건 아니지만, 유지보수의 측면에서 순수함수 를 작성하는게 좋다고 한다 순수함수: 오직 함수의 입력만이 함수의 결과에 영향을 주는 함수
- 기본 매개변수는 항상 뒤쪽에 배치하기
[!black]- 에시
// bad function handleThings(opts = {}, name) { // ... } // good function handleThings(name, opts = {}) { // ... }
-
절대로 새로운 함수를 만들기 위해 함수 생성자를 사용하지 말 것 함수 생성자 쓰지마! (new Function ())
-
함수 시그니처에 공백 넣기 function함수명(){}
[!black]- 예시
// bad const f = function () {}; const g = function () {}; const h = function () {}; // good const x = function () {}; const y = function a() {};
- 절대로 매개변수를 바꾸지 말기 C++ 에서 const로 변수를 선언하는것 처럼 매개변수 건들지 않기
[!black]- 예시
// bad function f1(obj) { obj.key = 1; } // good function f2(obj) { const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; }
재귀함수에서 배열에 값을 담는 상황이면 어떡해야하지..?
- 절대로 매개변수를 재할당하지 않기 매개변수를 재할당 하는것은 예측할 수 없는 결과를 불러 일으킵니다. 특히 arguments를 사용할때 말이죠 또한 V8에서 최적화 문제를 일으킬 수 있습니다
[!black]- 예시
// 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) { // ... }
-
가변인자 함수를 호출할 때는 전개 구문을 사용 그냥 하던대로 … 사용하면 됨
-
여러 줄의 시그니처 또는 호출을 취하는 함수는 이 가이드에 있는 다른 것처럼 들여 쓰기를 해야함 한줄에 각 항목을 하나씩 두고, 마지막 항목에 쉼표를 넣는다
[!black]- 예시
// bad function foo(bar, baz, quux) { // ... } // good function foo(bar, baz, quux) { // ... } // bad console.log(foo, bar, baz); // good console.log(foo, bar, baz);
화살표 함수
- 익명함수를 사용할 때에는 화살표 함수 표현을 사용
[!black]- 예시
// 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; });
- 하나의 식으로 구성된 함수가 사이드이펙트가 없는 표현식을 반환할 경우, 중괄호를 생략, 암시적 반환가능 그외의 경우는 중괄호도 사용하고, return도 사용할 것
[!black]- 예시
// bad [1, 2, 3].map((number) => { const nextNumber = number + 1; `A string containing the ${nextNumber}.`; }); // good [1, 2, 3].map((number) => `A string containing the ${number}.`); // good [1, 2, 3].map((number) => { const nextNumber = number + 1; return `A string containing the ${nextNumber}.`; }); // good [1, 2, 3].map((number, index) => ({ [index]: number, })); // 암시적 반환없이 사이드 이펙트를 수반합니다 function foo(callback) { const val = callback(); if (val === true) { // callback이 참을 반환하면 뭔가를 수행합니다 } } let bool = false; // bad bool 이라는 외부변수가 바뀌는 사이드이펙트가 있으니 중괄호로 감싸야함 foo(() => (bool = true)); // good foo(() => { bool = true; });
- 표현식이 여려 줄에 걸쳐 있을 때는 가독성을 높히기 위해 소괄호 사용
[!black]- 예시
// bad ['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call( httpMagicObjectWithAVeryLongName, httpMethod ) ); // good ['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call( httpMagicObjectWithAVeryLongName, httpMethod ) );
-
명확성과 일관성을 위해 인자를 괄호로 감싸기 .map((x) ⇒ x _ x); [O].map(x ⇒ x _ x); [X]
-
화살표 함수 구문을 비교연산자와 헷갈리지 않게 작성하기
[!black]- 예시
// bad const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize; // bad const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize; // good const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize; // good const itemHeight = (item) => { const { height, largeSize, smallSize } = item; return height > 256 ? largeSize : smallSize; };
- 암시적 반환을 하는 화살표 함수의 몸체의 위치를 적절하게 설정하기
[!black]- 예시
// bad (foo) => bar; (foo) => bar; // good (foo) => bar; (foo) => bar; (foo) => bar;
클래스 & 생성자
prototype을 직접 조작하는 것은 피하고, 항상class을 사용
[!black]- 예시
// 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를 사용 그냥 하던대로 하면 됨, 다른 방법도 있지만 그건 사용하지 않는다고 한다 -
메소드가
this를 반환하게 함으로써 메소드 체이닝을 할 수 있음
[!black]- 예시
// 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);
toString()을 사용해도 되지만, 올바르게 동작하는지와,사이드 이펙트가 없는지 확인하기 음.. 근데 어지간하면 다른함수명 사용하자..
[!black]- 예시
class Jedi { constructor(options = {}) { this.name = options.name || 'no name'; } getName() { return this.name; } toString() { return `Jedi - ${this.getName()}`; } }
- 클래스는 생성자가 명시되지 않은 경우 기본 생성자를 갖음 빈생성자 함수나, 부모 클래스로 위임하는 함수는 불필요함
[!black]- 예시
// 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'; } }
- 중복되는 클래스 멤버를 만들지 말기 하던대로 하면됨, 그냥 클래스 내에서 같은 이름 쓰지말라는 소리
[!black]- 예시
// bad class Foo { bar() { return 1; } bar() { return 2; } } // good class Foo { bar() { return 1; } } // good class Foo { bar() { return 2; } }
- 클래스 메소드는
this를 사용하거나, 해당 메소드를 정적 메소드로 만들어야 함 생성한 클래스 인스턴스의 속성에 따라 클래스 메소드가 다르게 동작해야한다 (그동안 해오던 대로) this를 사용하지 않는 함수는 정적메소드로 빼라는뜻
[!black]- 예시
// bad class Foo { bar() { console.log('bar'); } } // good - this를 사용했습니다 class Foo { bar() { console.log(this.bar); } } // good - constructor가 면제됩니다 class Foo { constructor() { // ... } } // good - 정적 메소드는 this를 사용하지 않는다고 예상할 수 있습니다 class Foo { static bar() { console.log('bar'); } }
모듈
- 항상 모듈(
import/export) 을 비표준 모듈 체계 대신 사용 쉽게 말해 require말고, import export 사용해라
[!black]- 예시
// 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는 쓰지 말기 import문으로부터 바로export하지말기 한줄이 간편하긴 하지만, 명확한 import 와 명확한 export 를 통해 일관성을 얻을 수 있음
[!black]- 예시
// bad // filename es6.js export { es6 as default } from './AirbnbStyleGuide'; // good // filename es6.js import { es6 } from './AirbnbStyleGuide'; export default es6;
- 같은 경로는 한 곳에
import하기 같은 경로에서 하는 여러 줄의 import 는 유지보수를 힘들게 함
[!black]- 예시 // bad import foo from ‘foo’; // … 또 다른 imports … // import { named1, named2 } from ‘foo’;
// good import foo, { named1, named2 } from ‘foo’;
// good import foo, { named1, named2, } from ‘foo’;
- 가변 바인딩을
export하지 말기 일반적으로 상수 참조(const)만 export 되어야 함
[!black]- 예시
// bad let foo = 3; export { foo }; // good const foo = 3; export { foo };
- 한가지만
export하는 모듈에서는default export사용하기 import구문을 다른 구문들 위에 두기- 여러 줄에 걸친
import는 들여쓰기 하기 - 모듈
import구문에Webpack loader구문 사용하지 말기 import 에서 Webpack 구문을 사용하면 이 코드가 모듈 번들러에 연결됨, loader 구문은 webpack.config.js 에서 사용
[!black]- 예시
// 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';
- 자바스크립트 파일 확장자명을 명시하지 말기 리팩토링을 제한시킨다
[!black]- 예시
// 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-in이나for-of대신 자바스크립트의 고급함수 사용 고급함수는 불변 규칙을 적용한다. 사이드이펙트에 대해 추측하는것보다 순수함수를 다루는 것이 더 쉽다
[!black]- 예시
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);
white
배열을 이터레이트할 때
map()every()filter()find()findIndex()reduce()some()을 사용 배열을 생성할 때는Object.keys()/Object.values()/Object.entries()를 사용 개인적으로 가장 충격적이었던 사실..
-
당분간은 제네레이터 사용하지 말기 ES5로 트랜스파일이 잘 안됨 트랜스파일: 한 언어로 작성된 소스코드가 비슷한 수준의 추상화를 가진 다른언어로 변환하는 것
-
만약 제네레이터를 사용할거면, 함수 시그니처의 공백이 적절한지 확인
*function과*는 같은 개념의 키워드,function*로 사용해야 적절함,function * [X]* 근데 쓰지 말라니까 걍 쓰지마
속성
- 속성에 접근할 떄 마침표를 사용
[!black]- 예시
const luke = { jedi: true, age: 28, }; // bad const isJedi = luke['jedi']; // good const isJedi = luke.jedi;
- 변수를 사용해서 속성에 접근할떄
[]사용
[!black]- 예시
const luke = { jedi: true, age: 28, }; function getProp(prop) { return luke[prop]; } const isJedi = getProp('jedi');
- **제곱 연산할 떄 제곱연산자
**사용**
[!black]- 예시
// bad const binary = Math.pow(2, 10); // good const binary = 2 ** 10;
이미 한번 당함 (Math.pow는 실수연산이라 큰 숫자에서 오차가 생김)
변수
-
변수를 선언할 때는 항상
const와let만 사용 그렇지 않으면 전역 변수로 선언된다. 전역 스페이스를 오염시키지 않기를 바란다 -
하나의 변수 선언 / 할당에는 하나의
const나let을 사용 디버거로 선언을 단계별로 살펴볼 수 있다
[!black]- 예시
// 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';
const를 그룹화한 다음let을 사용 const 먼저 쭉 쓰고 let 을 쓰라는 뜻
[!black]- 예시
// 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;
- 필요한 곳에서 변수를 할당한되, 합당한 곳에 두기 let 과 const는 블록 스코프이지, 함수 스코프가 아님
[!black]- 예시
// 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; }
코드 윗쪽에서 사용할 변수를 전부 선언해야하는 강박에서 자유로워질수 있다
- 변수 할당 체이닝을 사용하지 않기 변수할당 체이닝은 암시 전역변수를 만든다
[!black]- 예시
// 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`에도 동일하게 적용됩니다
- 단항 증감 연산자를 사용하지 말기
오류를 일으킬 수 있고,
num += 1과 같은 구문으로 값을 변경하는것이++,--구문을 사용하는것보다 의미있는 일이라고 생각된다
이것도 좀 충격적이네
- 값을 할당할 때
=앞 뒤에서 줄 바꿈하지 말기 할당하는 값의 길이가 길어질 경우 값을 괄호로 둘러싸기
[!black]- 예시
// bad const foo = superLongLongLongLongLongLongLongLongFunctionName(); // bad const foo = 'superLongLongLongLongLongLongLongLongString'; // good const foo = superLongLongLongLongLongLongLongLongFunctionName(); // good const foo = 'superLongLongLongLongLongLongLongLongString';
- 사용하지 않는 변수 남겨두지 말기
호이스팅
- let과 const 는 Temporal Dead Zones (TDZ)이라고 불리는 새로운 개념의 혜택을 받음
var는 가장 가까운 함수스코프 꼭대기에 호이스팅 되는다는데 (
안쓸거니까 알 필요없다)
[!black]- 예시
// (전역 변수 notDefined가 존재하지 않는다고 판정한 경우) // 동작하지 않습니다 function example() { console.log(notDefined); // => throws a ReferenceError } // 그 변수를 참조하는 코드의 뒤에서 그 변수를 선언한 경우 // 변수가 호이스트된 상태에서 동작합니다. // 주의:`true` 라는 값 자체는 호이스트되지 않습니다. function example() { console.log(declaredButNotAssigned); // => undefined var declaredButNotAssigned = true; } // 인터프리터는 변수선언을 스코프의 선두에 호이스트합니다 // 위의 예는 다음과 같이 다시 쓸수 있습니다: function example() { let declaredButNotAssigned; console.log(declaredButNotAssigned); // => undefined declaredButNotAssigned = true; } // const와 let을 이용한 경우 function example() { console.log(declaredButNotAssigned); // => throws a ReferenceError console.log(typeof declaredButNotAssigned); // => throws a ReferenceError const declaredButNotAssigned = true; }
- 익명 함수의 경우 함수가 할당되기 전의 변수가 호이스트 됨
[!black]- 예시
function example() { console.log(anonymous); // => undefined anonymous(); // => TypeError anonymous is not a function var anonymous = function () { console.log('anonymous function expression'); }; }
- 명명 함수의 경우도 똑같이 변수가 호이스트되고, 함수의 이름이나 본체는 호이스트 되지 않음
[!black]- 예시
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'); }; } // 함수 이름이 변수 이름과 동일할 때도 마찬가지다. function example() { console.log(named); // => undefined named(); // => TypeError named is not a function var named = function named() { console.log('named'); }; }
- 함수 선언은 함수의 이름과 본체가 호이스트 됨
비교 연산자
- ”==”, ”!=” 대신 ”===”, ”!==” 사용
if문 과 같은 조건식은ToBoolean메소드에 의해 강제형변환이 되어 항상 다음과 같은 규칙을 따름- *Object는 true로 평가*
- *Undefined는 false로 평가*
- *Null은 false로 평가*
- *Booleans는 boolean형의 값으로 평가*
- *Numbers는 true로 평가, 하지만 +0, -0, Nan의 경우 false로 평가*
- *String은 true로 평가, 하지만
‘’은 false로 평가*
[!black]- 예시
if ([0] && []) { // true // 배열(빈 배열 포함)은 객체이며, 객체는 참으로 평가됩니다. }
- Boolean 비교는 단축형을 사용, 단 숫자나 문자열은 명시적으로 비교
[!black]- 예시
// bad if (isValid === true) { // ... } // good if (isValid) { // ... } // bad if (name) { // ... } // good if (name !== '') { // ... } // bad if (collection.length) { // ... } *이것도 좀 간과하기 쉬운 컨벤션인듯 더 자세한 내용은* [Truth Equality and JavaScript](https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108)
- 렉시컬 선언(
let,const,function,class) 을 포함하는switch문 안에 블록을 만들 떄 괄호 사용하기
[!black]- 예시
// bad switch (foo) { case 1: let x = 1; break; case 2: const y = 2; break; case 3: function f() { // ... } break; default: class C {} } // good switch (foo) { case 1: { let x = 1; break; } case 2: { const y = 2; break; } case 3: { function f() { // ... } break; } case 4: bar(); break; default: { class C {} } }
- 삼항 연산자를 중첩해서는, 안되며 일반적으로 한줄로 표현
- 불필요한 삼항 연산자는 사용하지 말기 어지간하면 삼항 연산자는 사용하는걸 피하자
[!black]- 예시
// bad const foo = a ? a : b; const bar = c ? true : false; const baz = c ? false : true; // good const foo = a || b; const bar = !!c; const baz = !c;
- 연산자를 섞어 사용할 때 해당 연산자들을 괄호로 둘러싸기 코드가 더 읽기쉬우지고, 개발자의 의도가 명확해짐
[!black]- 예시
// bad const foo = (a && b < 0) || c > 0 || d + 1 === 0; // bad const bar = a ** b - (5 % d); // bad // (a || b) && c 으로 혼동할 수 있습니다. if (a || (b && c)) { return d; } // good const foo = (a && b < 0) || c > 0 || d + 1 === 0; // good const bar = a ** b - (5 % d); // good if (a || (b && c)) { return d; } // good const bar = a + (b / c) * d;
블록
- 여러 줄의 블록에는 중괄호를 사용 해오던대로 하면 됨
[!black]- 예시
// bad if (test) return false; // good if (test) return false; // good if (test) { return false; } // bad function foo() { return false; } // good function bar() { return false; }
- 여러줄의 if 와 else 문을 사용 할때에는, else 를 if 블록의 닫는 중괄호와 같은 줄에 두기
[!black]- 예시
// bad if (test) return false; // good if (test) return false; // good if (test) { return false; } // bad function foo() { return false; } // good function bar() { return false; }
if블록이 항상return구문을 실행한다면else블록은 불필요함 if 블록을 잇는 else if 문에 return 구문이 있으면 여러 if 문으로 나누어질 수 있음
[!black]- 예시
// bad function foo() { if (x) { return x; } else { return y; } } // bad function cats() { if (x) { return x; } else if (y) { return y; } } // bad function dogs() { if (x) { return x; } else { if (y) { return y; } } } // good function foo() { if (x) { return x; } return y; } // good function cats() { if (x) { return x; } if (y) { return y; } } // good function dogs(x) { if (x) { if (z) { return y; } } else { return z; } }
제어문
- 제어문(
if,while)이 너무 긴 경우, 각 조건을 새로운 줄에 두기. 논리 연산자는 줄의 시작부분에 와야함
[!black]- 예시
// bad if ( (foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening() ) { thing1(); } // bad if (foo === 123 && bar === 'abc') { thing1(); } // bad if (foo === 123 && bar === 'abc') { thing1(); } // bad if (foo === 123 && bar === 'abc') { thing1(); } // good if (foo === 123 && bar === 'abc') { thing1(); } // good if ( (foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening() ) { thing1(); } // good if (foo === 123 && bar === 'abc') { thing1(); }
- 선택연산자를 제어구문대신 쓰지 말기
[!black]- 예시
// bad !isRunning && startRunning(); // good if (!isRunning) { startRunning(); }
주석
- **여러 줄에 걸쳐 주석을 작성할 때에는
/** … \*/을 사용하기**
[!black]- 예시
// bad // make()는 전달된 태그명을 기반으로 // 새로운 요소를 반환한다. // // @param {String} tag // @return {Element} element function make(tag) { // ... return element; } // good /** * make()는 전달된 태그명을 기반으로 * 새로운 요소를 반환한다. */ function make(tag) { // ... return element; }
- 한 줄 주석을 사용 할때에는
//를 사용하기. 주석 전에는 빈행을 넣기
[!black]- 예시
// bad const active = true; // is current tab // good // is current tab const active = true; // bad function getType() { console.log('fetching type...'); // set the default type to 'no type' const type = this.type || 'no type'; return type; } // good function getType() { console.log('fetching type...'); // set the default type to 'no type' const type = this.type || 'no type'; return type; } // also good function getType() { // set the default type to 'no type' const type = this.type || 'no type'; return type; }
- 모든 주석은 공백으로 시작해야함
[!black]- 예시
// bad //is current tab const active = true; // good // is current tab const active = true; // bad /** *make()는 전달된 태그명을 기반으로 *새로운 요소를 반환한다. */ function make(tag) { // ... return element; } // good /** * make()는 전달된 태그명을 기반으로 * 새로운 요소를 반환한다. */ function make(tag) { // ... return element; }
-
문제를 지적하거나 재고를 요구하는 경우, 주석 앞에
FIXME,TODO를 붙임 다른 개발자에게 빠른 이해를 도울 수 있음 -
문제에 대한 주석은
// FIXME:사용
[!black]- 예시
class Calculator extends Abacus { constructor() { super(); // FIXME: 전역 변수를 사용해서는 안 됨 total = 0; } }
- 문제의 해결책에 대한 주석은
// TODO:사용
[!black]- 예시
class Calculator extends Abacus { constructor() { super(); // TODO: total은 옵션 파라메터로 설정해야함 this.total = 0; } }
공백
- 탭은 공백문자 두개로 작성하기 난 지금까지 4칸으로 썼는데 2칸으로 줄여야겠다
[!black]- 예시
// bad function foo() { ∙∙∙∙let name; } // bad function bar() { ∙let name; } // good function baz() { ∙∙let name; }
- 주요 중괄호 앞에는 공백문자 한개 넣기
[!black]- 예시
// bad function test() { console.log('test'); } // good function test() { console.log('test'); } // bad dog.set('attr', { age: '1 year', breed: 'Bernese Mountain Dog', }); // good dog.set('attr', { age: '1 year', breed: 'Bernese Mountain Dog', });
- 제어문 (
if,while) 의 소괄호 앞에는 공백 하나 넣기, 함수선언이나 호출시 인자앞 공백 넣지 말기 함수에서 사용하는 소괄호에는 공백넣지 말기 기억
[!black]- 예시
// bad if (isJedi) { fight(); } // good if (isJedi) { fight(); } // bad function fight() { console.log('Swooosh!'); } // good function fight() { console.log('Swooosh!'); }
- 파일 끝에 개행문자 1개 넣기 그니까 파일 끝은 무조건 개행문자로만 끝나게 만들라는 뜻
[!black]- 예시
// bad import { es6 } from './AirbnbStyleGuide'; // ... export default es6; // bad import { es6 } from './AirbnbStyleGuide'; // ... export default es6;↵ ↵ // good import { es6 } from './AirbnbStyleGuide'; // ... export default es6;↵
- 길게 메소드 체이닝하는 경우(2개이상) 들여쓰기를 하기, 그리고 마침표를 맨 앞에 두기
[!black]- 예시
// bad $('#items').find('.selected').highlight().end().find('.open').updateCount(); // bad $('#items').find('.selected').highlight().end().find('.open').updateCount(); // good $('#items').find('.selected').highlight().end().find('.open').updateCount(); // bad const leds = stage .selectAll('.led') .data(data) .enter() .append('svg:svg') .classed('led', true) .attr('width', (radius + margin) * 2) .append('svg:g') .attr('transform', `translate(${radius + margin},${radius + margin})`) .call(tron.led); // good const leds = stage .selectAll('.led') .data(data) .enter() .append('svg:svg') .classed('led', true) .attr('width', (radius + margin) * 2) .append('svg:g') .attr('transform', `translate(${radius + margin},${radius + margin})`) .call(tron.led); // good const leds = stage.selectAll('.led').data(data);
- 구문의 앞과 블록의 뒤에는 빈 행을 두기
[!black]- 예시
// 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;
- 블록에 빈행을 끼워 넣지 말기 그냥 블록에서 컴팩트하게 적으라는 거 같다
[!black]- 예시
// bad function bar() { console.log(foo); } // bad if (baz) { console.log(qux); } else { console.log(foo); } // bad class Foo { constructor(bar) { this.bar = bar; } } // good function bar() { console.log(foo); } // good if (baz) { console.log(qux); } else { console.log(foo); }
- 여러 빈행을 두지 않기 깔끔해 보이려고 빈행을 억지로 넣지 말아라
[!black]- 예시
// bad class Person { constructor(fullName, email, birthday) { this.fullName = fullName; this.email = email; this.setAge(birthday); } setAge(birthday) { const today = new Date(); const age = this.getAge(today, birthday); this.age = age; } getAge(today, birthday) { // .. } } // good class Person { constructor(fullName, email, birthday) { this.fullName = fullName; this.email = email; this.setAge(birthday); } setAge(birthday) { const today = new Date(); const age = getAge(today, birthday); this.age = age; } getAge(today, birthday) { // .. } }
- 소괄호 안쪽에 공백 두지 않기
- 대괄호 안쪽에 공백 두지 않기
[!black]- 예시
// 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]);
- 중괄호 안쪽에는 공백 두기
[!black]- 예시
// bad const foo = { clark: 'kent' }; // good const foo = { clark: 'kent' };
- 한 줄에 코드가 100자 넘는것은 피하기 (공백포함) 긴문자열인 경우는 예외 (문자열 길다고 분리해서 쓰면 안됨)
[!black]- 예시
// bad const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; // bad $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' }, }) .done(() => console.log('Congratulations!')) .fail(() => console.log('You have failed this city.')); // good const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; // good $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' }, }) .done(() => console.log('Congratulations!')) .fail(() => console.log('You have failed this city.'));
-
쉼표 이전에는 공백넣지말고, 이후에 공백넣기 하던대로 하면됨
-
계산된 속성 내에서는 공백을 넣으세요
[!black]- 예시
// bad obj[foo]; obj['foo']; var x = { [b]: a }; obj[foo[bar]]; // good obj[foo]; obj['foo']; var x = { [b]: a }; obj[foo[bar]];
white
eslint:
computed-property-spacing
*"never"(default) disallows spaces inside computed property brackets**"always"requires one or more spaces inside computed property brackets*이 말이 애매해서 찾아봤는데 그냥
“never”을 사용하라는 뜻인듯 싶다
- 함수 호출할떄 공백 넣지 말기
- 객체 리터럴 속성의 키와 값 사이에는 공백 넣기
[!black]- 예시
// bad var obj = { foo: 42 }; var obj2 = { foo: 42 }; // good var obj = { foo: 42 };
- 행의 마지막에 공백 남겨놓지 말기
- 여러 빈행을 쓰지 말기, 파일의 맨앞에 빈행 쓰지 말기 파일 끝에는 마지막행에는 빈행 하나두기
[!black]- 예시
// bad - 여러 개의 빈 줄 var x = 1; var y = 2; // bad - 파일 끝에 2개 이상의 빈 줄 var x = 1; var y = 2; // bad - 파일 시작에 1개 이상의 빈 줄 var x = 1; var y = 2; // good var x = 1; var y = 2;
쉼표
- 쉼표는 항상 뒤에 나머지요소 (…args) 뒤에는 쉼표가 없다
[!black]- 예시
// bad const story = [once, upon, aTime]; // good const story = [once, upon, aTime]; // bad const hero = { firstName: 'Ada', lastName: 'Lovelace', birthYear: 1815, superPower: 'computers', }; // good const hero = { firstName: 'Ada', lastName: 'Lovelace', birthYear: 1815, superPower: 'computers', };// bad - 마지막에 쉼표가 없는 경우 git diff const hero = { firstName: 'Florence', - lastName: 'Nightingale' + lastName: 'Nightingale', + inventorOf: ['coxcomb chart', 'modern nursing'] }; // good - 마지막에 쉼표가 있는 경우 git diff const hero = { firstName: 'Florence', lastName: 'Nightingale', + inventorOf: ['coxcomb chart', 'modern nursing'], };
쉼표를 뒤에 붙이는 스타일을 유지해야만 git diffs에 불필요한 정보들이 들어가지 않는다
세미콜론
- 세미콜론 쓰자 하던대로 하면된다
형변환 강제
- 구문의 선두에서 형 강제를 하자
- 문자열 String 으로 형변환 시키자 원시타입에 new를 붙여서 초기화하면 Object가 된다, new 붙이지 말기
[!black]- 예시
// => this.reviewScore = 9; // bad const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string" // bad const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf() // bad const totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string // good const totalScore = String(this.reviewScore);
- 숫자를 형 변환하는 경우 Number를 사용하고, parseInt를 사용하는 경우 기수도 명시를 해줘야 함
10진수로 변환의 경우,
Number(numStr)이나parseInt(numStr, 10)를 사용하라는 뜻
[!black]- 예시
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);
- 어떤 이유에서인지
parseInt가 병목현상을 일으켜 성능상의 이슈로 비트 시프트를 사용해야하는 경우 하려고했던 것을 왜(why)와 무엇을(what) 주석으로 남겨라
[!black]- 예시
// good /** * parseInt was the reason my code was slow. * Bitshifting the String to coerce it to a * Number made it a lot faster. * 코드가 느린 원인은 parseInt였음. * 비트 시프트를 통해 문자열을 강제 형변환하여 * 성능을 개선시킴. */ const val = inputValue >> 0;
- 주의: 비트연산자를 사용하는경우, 숫자는 64비트로 표현되어 있으나, 비트시프트를 사용하는경우 32비트 정수로 넘겨짐 따라서 숫자가 32비트 이상 넘어가면 예기치못한 현상을 야기할수 있음
[!black]- 예시
2147483647 >> 0; // => 2147483647 2147483648 >> 0; // => -2147483648 2147483649 >> 0; // => -2147483647
- 불리언
[!black]- 예시
const age = 0; // bad const hasAge = new Boolean(age); // good const hasAge = Boolean(age); // best const hasAge = !!age;
명명 규칙
- 한 문자로 된 이름은 피해라 이름으로부터 의도가 읽혀질수 있도록 해라
[!black]- 예시
// bad function q() { // ... } // good function query() { // ... }
- 객체, 함수, 인스턴스에는 캐멀케이스(camelCase)를 사용
[!black]- 예시
// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
- 클래스나 생성자에는 파스칼케이스(PascalCase)를 사용
[!black]- 예시
// bad function user(options) { this.name = options.name; } const bad = new user({ name: 'nope', }); // good class User { constructor(options) { this.name = options.name; } } const good = new User({ name: 'yup', });
- 언더스코어를 사용하지 마라 자바스크립트는 속성이나 메소드 측면에서 은닉된 정보라는 개념을 갖고 있지않다. 언더스코어는 일반적으로 “private” 을 의미하지만 자바스크립트에서 해당 속성은 완전히 public하다. 요약 자바스크립트에서 뭔가 private하게 사용하고싶다면, 그것을 불가능하다
[!black]- 예시
// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; this._firstName = 'Panda'; // good this.firstName = 'Panda'; // good, in environments where WeakMaps are available // see https://kangax.github.io/compat-table/es6/#test-WeakMap const firstNames = new WeakMap(); firstNames.set(this, 'Panda');
- 참조에
this를 저장하지 말기 화살표 함수나, Function#bind 사용
[!black]- 예시
// bad function foo() { const self = this; return function () { console.log(self); }; } // bad function foo() { const that = this; return function () { console.log(that); }; } // good function foo() { return () => { console.log(this); }; }
[!white]
bind, apply, call예시공통점: 전부 첫번째 인자가 this의 값으로 들어감차이점: bind는 말그대로 값들과 함수나 클래스를 묶어주는 느낌, apply, call은 즉시 호출apply, call의 차이점: apply는 배열을 인자로 쓰고, call은 각각 변수를 인자롤 쓴다function sum(a, b, c) { return a + b + c; } const sum123 = sum.bind(null, 1, 2, 3); const arr = [1, 2, 3]; console.log(sum123()); // 6 console.log(sum.apply(null,arr)); // 6 console.log(sum.call(null, 1, 2, 3)); // 6
- 파일 이름은 default export의 이름과 일치해야 함 대문자든 소문자든간에 파일이름은 default export의 이름과 일치해야한다
[!black]- 예시
// 파일 1 내용 class CheckBox { // ... } export default CheckBox; // 파일 2 내용 export default function fortyTwo() { return 42; } // 파일 3 내용 export default function insideDirectory() {} // 다른 파일 // bad import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export // bad import CheckBox from './check_box'; // PascalCase import/export, snake_case filename import forty_two from './forty_two'; // snake_case import/filename, camelCase export import inside_directory from './inside_directory'; // snake_case import, camelCase export import index from './inside_directory/index'; // requiring the index file explicitly import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly // good import CheckBox from './CheckBox'; // PascalCase export/import/filename import fortyTwo from './fortyTwo'; // camelCase export/import/filename import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index" // ^ supports both insideDirectory.js and insideDirectory/index.js
- 함수를 export default할 때 캐멀케이스 사용하기, 파일이름과 함수이름은 같아야 함
- 생성자 / 클래스 / 싱글톤 / 함수 라이브러리 / 단순 객체를 export 할 때에는 파스칼케이스 사용하기 헷갈릴만한데, export하는 객체의 경우는 파스칼케이스로 쓰라한다 / 일반적으로는 캐멀케이스
[!black]- 예시
const AirbnbStyleGuide = { es6: {}, }; export default AirbnbStyleGuide;
- 두 문자어나 이니셜은 모두 대문자거나 소문자여야 함 이름은 가독성을 위한것이지, 컴퓨터 알고리즘을 위한 것이 아니다
[!black]- 예시
// bad import SmsContainer from './containers/SmsContainer'; // bad const HttpRequests = [ // ... ]; // good import SMSContainer from './containers/SMSContainer'; // good const HTTPRequests = [ // ... ]; // also good const httpRequests = [ // ... ]; // best import TextMessageContainer from './containers/TextMessageContainer'; // best const requests = [ // ... ];
- 선택적으로 변수이름을 대문자들로 지을수 있음
대문자로 이름을 지을때는 언더스코어도 써도 되는거 같다
- export일때
- const일 때
모든
const변수 이름을 대문자로 짓나요? - 이것은 필수사항이 아니며, 파일 내 상수 이름을 꼭 대문자로 지을 필요는 없습니다. 하지만 내보내기되는 상수 이름은 대문자로 지어야 합니다. - 프로그래머가 해당 변수와 그 속성이 변하지 않을것이라 확신할 때
내보내기 되는 객체 이름을 대문자로 짓나요? - 최상위 수준의 내보내기를 할 때 대문자로 이름짓고 (예시:
EXPORTED_OBJECT.key) 모든 중첩된 속성이 변경되지 않도록 유지합니다.
[!black]- 예시
// bad const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file'; // bad export const THING_TO_BE_CHANGED = 'should obviously not be uppercased'; // bad export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables'; // --- // allowed but does not supply semantic value export const apiKey = 'SOMEKEY'; // better in most cases export const API_KEY = 'SOMEKEY'; // --- // bad - unnecessarily uppercases key while adding no semantic value export const MAPPING = { KEY: 'value', }; // good export const MAPPING = { key: 'value', };
접근자
- 속성을 위한 접근자 함수는 필수가 아님
- 자바스크립트의
getters/setters를 사용하지 마라 예기치 못한 사이드이펙트를 일으키고, 테스트와 유지보수를 힘들게 한다
[!black]- 예시
// bad class Dragon { get age() { // ... } set age(value) { // ... } } // good class Dragon { getAge() { // ... } setAge(value) { // ... } }
- 속성이나 메소드가
boolean이라면,isVal이나hasVal을 사용
[!black]- 예시
// bad if (!dragon.age()) { return false; } // good if (!dragon.hasAge()) { return false; }
- get(), set() 함수를 만들되, 일관성있게 만들기
[!black]- 예시
class Jedi { constructor(options = {}) { const lightsaber = options.lightsaber || 'blue'; this.set('lightsaber', lightsaber); } set(key, val) { this[key] = val; } get(key) { return this[key]; } }
이벤트
- (DOM 이나 BackBone 이벤트같은) 이벤트로 payload 값을 넘기는 경우, raw 값보다, 객체리터럴 (해시값) 을 넘겨라 이후 contributors 들이 이벤트와 관련한 모든 이벤트 핸들러를 바꾸는 대신, 이벤트 payload의 값을 추가할 수 있다.
[!black]- 예시
// bad $(this).trigger('listingUpdated', listing.id); // ... $(this).on('listingUpdated', (e, listingID) => { // do something with listingID }); // good $(this).trigger('listingUpdated', { listingID: listing.id }); // ... $(this).on('listingUpdated', (e, data) => { // do something with data.listingID });
제이쿼리
- 제이쿼리 객체 변수 앞에
$를 붙여라
[!black]- 예시
// bad const sidebar = $('.sidebar'); // good const $sidebar = $('.sidebar'); // good const $sidebarBtn = $('.sidebar-btn');
- 제이쿼리의 검색결과 를 캐시 쓸 때마다 호출해서 찾지말고, 찾은값을 변수에 담아놓으라는 뜻
[!black]- 예시
// bad function setSidebar() { $('.sidebar').hide(); // ... $('.sidebar').css({ 'background-color': 'pink', }); } // good function setSidebar() { const $sidebar = $('.sidebar'); $sidebar.hide(); // ... $sidebar.css({ 'background-color': 'pink', }); }
- DOM검색에는
$(’.sidebar ul’)이나 parent > child$(’.sidebar > ul’)과 같은 캐스캐이딩을 사용 - 한정된 제이쿼리 객체 춰리에서는
find사용
[!black]- 예시
// bad $('ul', '.sidebar').hide(); // bad $('.sidebar').find('ul').hide(); // good $('.sidebar ul').hide(); // good $('.sidebar > ul').hide(); // good $sidebar.find('ul').hide();