참조
- 모든 참조에는
var대신const를 쓰기 참조를 재할당 할수 없게 함으로써, 버그를 방지
// bad
var a = 1;
var b = 2;
// good
const a = 1;
const b = 2;
- 참조에 재할당을 해야하는 상황이면
let을 사용
// bad
var count = 1;
if (true) {
count += 1;
}
// good, use the let.
let count = 1;
if (true) {
count += 1;
}
const,let모두 블록단위 스코프임에 유의
객체
- 객체 생성시 리터럴 문법을 사용
객체 생성시
{}를 사용하라는 뜻
// bad
const item = new Object();
/ good
const item = {};
- 동적 속성을 갖는 객체는 속성 계산명을 사용
속성명이 바뀔수 있는 속성은 속성계산명
[Key]: value을 사용
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,
};
- 메소드의 단축구문을 사용 속성과 값의 이름이 동일하면 속성이름만 적기
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
- 단축구문을 사용한경우 객체의 최상단에 배치
- 유효하지 않은 식별자에만 따옴표 속성 사용 일반적인 속성은 따옴표 없이 표기
// 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메소드를 직접 호출하지 말기 객체의 속성에 의해 메소드가 가려질수 있음
const object = {
a: 1,
hasOwnProperty: false,
};
// 이 경우에는 오류가 발생합니다.
console.log(object.hasOwnProperty('a')); // TypeError: object.hasOwnProperty is not a function
// 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에선 원본 객체가 손상되는 것을 최대한으로 지양한다
// 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용어
// bad
const items = new Array();
// good
const items = [];
- 배열에 직접 값을 할당하지 말고, Array#push 사용
const someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
- 순회가능한 객체 (iterable object) 를 배열로 만들 때,
Array.from대신, … 구문을 사용 순회가능 객체가 뭐지? Iterable Object → (Array, String, Set, Map, …)
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,…)된 요소를 가진 객체)
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을 사용 중간 배열 생성을 방지
// bad
const baz = [...foo].map(bar);
// good
const baz = Array.from(foo, bar);
white
Array.from은 map에 비해 메모리는 적게쓰지만, 오래걸린다는 단점이 있음 StackOverFlow
- 배열 메소드 콜백에는 리턴 구문 사용
// 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번 인덱스를 초기값으록 가진다
- 배열이 여러줄에 걸쳐 있다면 배열을 연 이후와 닫기 이전에 줄바꿈하기
// 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];
비구조화
- 하나의 객체에서 여러 속성에 접근할 때에는 객체 비구조화 사용 속성들을 위한 임시 참조를 만들지 않게 해주고, 객체에 반복적인 접근방지
// 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}`;
}
- 배열 비구조화 를 사용
- 여러 값을 반환하는 경우 배열 비구조화 말고, 객체 비구조화 사용 배열 비구조화를 사용하려면 비구조화시 배열의 순서까지 고려해야하는 불편함이 있음
// 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.';
- 문자열을 생성하는 경우, 문자열 연결 대신, 템플릿 문자열 사용
// 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 -
문자열에 불필요한 이스케이프 문자 사용 자제 가독성을 해침
함수
- 함수선언식 말고 기명 함수표현식을 사용 함수 선언은 호이스팅 된다. 즉 함수가 선언되기 전에 함수를 참조하는것이 쉽다는 뜻 이는 유지보수에 어려움을 가져다 준다, 함수에 이름을 명시적으로 지정하면 디버깅 시 콜 스택에서 함수이름을 알 수 있다
// bad
function foo() {
// ...
}
// bad
const foo = function () {
// ...
};
// good
// 변수 참조 호출과 구분되는 이름
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};
- 즉시 함수 표현식을 괄호로 감싸기 괄호로 감싸면 괄호 안의 표현을 명확하게 해줌
// 즉시 호출 함수 표현식 (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
})();
white
즉시 함수 표현식에 방법은 여러 방법이 있지만 전체를 괄호로 묶는 방식을 사용하자 (function() {})() [X] (function() {}()) [O]
-
함수 이외의 블록(If, while, {}, 등)에서 함수를 선언하지 말기, 브라우저는 이를 허용하지만, 모두 다 다르게 해석한다
-
참고 ECMA-262 명세는
블록을 구문으로 명시하고 있지만 함수는 구문이 아님
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
let test;
if (currentUser) {
test = () = {
console.log('Yup.');
};
}
```코드컨벤션
**white**
표현식: 표현식은 값을 계산하고 반환합니다.
구문: 구문은 특정 작업을 수행하며, 프로그램의 흐름을 제어합니다.
[구문과 표현식](https://velog.io/@sangwook0613/Expression-%EA%B3%BC-Statement)
- **절대 함수의 매개변수 이름을 `arguments` 로 지으면 안됨**
*함수 스코프에 전해지는 arguments 객체의 참조를 덮어씀*
- **절대 `arguments` 를 사용하지 말기, 차라리 나머지 문법 `…` 사용하기**
*… 을 사용하면 매개변수를 몇개 사용할지 확실히 할수 있고, 나머지 문법을 사용한것은 진짜 Array인것에 반해 arguments는 Array-Like 객체가 아니다*
```jsx
// 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함수명(){}
// bad
const f = function () {};
const g = function () {};
const h = function () {};
// good
const x = function () {};
const y = function a() {};
- 절대로 매개변수를 바꾸지 말기 C++ 에서 const로 변수를 선언하는것 처럼 매개변수 건들지 않기
// bad
function f1(obj) {
obj.key = 1;
}
// good
function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, 'key')
? obj.key
: 1;
}
재귀함수에서 배열에 값을 담는 상황이면 어떡해야하지..?
- 절대로 매개변수를 재할당하지 않기 매개변수를 재할당 하는것은 예측할 수 없는 결과를 불러 일으킵니다. 특히 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) {
// ...
}
-
가변인자 함수를 호출할 때는 전개 구문을 사용 그냥 하던대로 … 사용하면 됨
-
여러 줄의 시그니처 또는 호출을 취하는 함수는 이 가이드에 있는 다른 것처럼 들여 쓰기를 해야함 한줄에 각 항목을 하나씩 두고, 마지막 항목에 쉼표를 넣는다
// bad
function foo(bar, baz, quux) {
// ...
}
// good
function foo(bar, baz, quux) {
// ...
}
// bad
console.log(foo, bar, baz);
// good
console.log(foo, bar, baz);
화살표 함수
- 익명함수를 사용할 때에는 화살표 함수 표현을 사용
// 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도 사용할 것
// 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;
});
- 표현식이 여려 줄에 걸쳐 있을 때는 가독성을 높히기 위해 소괄호 사용
// 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]
-
화살표 함수 구문을 비교연산자와 헷갈리지 않게 작성하기
// 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;
};
- 암시적 반환을 하는 화살표 함수의 몸체의 위치를 적절하게 설정하기
// bad
(foo) = bar;
(foo) = bar;
// good
(foo) = bar;
(foo) = bar;
(foo) = bar;
클래스 & 생성자
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를 사용 그냥 하던대로 하면 됨, 다른 방법도 있지만 그건 사용하지 않는다고 한다 -
메소드가
this를 반환하게 함으로써 메소드 체이닝을 할 수 있음
// 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()을 사용해도 되지만, 올바르게 동작하는지와,사이드 이펙트가 없는지 확인하기 음.. 근데 어지간하면 다른함수명 사용하자..
class Jedi {
constructor(options = {}) {
this.name = options.name || 'no name';
}
getName() {
return this.name;
}
toString() {
return `Jedi - ${this.getName()}`;
}
}
- 클래스는 생성자가 명시되지 않은 경우 기본 생성자를 갖음 빈생성자 함수나, 부모 클래스로 위임하는 함수는 불필요함
// 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';
}
}
- 중복되는 클래스 멤버를 만들지 말기 하던대로 하면됨, 그냥 클래스 내에서 같은 이름 쓰지말라는 소리
// bad
class Foo {
bar() {
return 1;
}
bar() {
return 2;
}
}
// good
class Foo {
bar() {
return 1;
}
}
// good
class Foo {
bar() {
return 2;
}
}
- 클래스 메소드는
this를 사용하거나, 해당 메소드를 정적 메소드로 만들어야 함 생성한 클래스 인스턴스의 속성에 따라 클래스 메소드가 다르게 동작해야한다 (그동안 해오던 대로) this를 사용하지 않는 함수는 정적메소드로 빼라는뜻
// 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 사용해라
// 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 를 통해 일관성을 얻을 수 있음
// bad
// filename es6.js
export { es6 as default } from './AirbnbStyleGuide';
// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;
- 같은 경로는 한 곳에
import하기 같은 경로에서 하는 여러 줄의 import 는 유지보수를 힘들게 함
// 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 되어야 함
// 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 에서 사용
// 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';
- 자바스크립트 파일 확장자명을 명시하지 말기 리팩토링을 제한시킨다
// 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대신 자바스크립트의 고급함수 사용 고급함수는 불변 규칙을 적용한다. 사이드이펙트에 대해 추측하는것보다 순수함수를 다루는 것이 더 쉽다
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]* 근데 쓰지 말라니까 걍 쓰지마
속성
- 속성에 접근할 떄 마침표를 사용
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');
- **제곱 연산할 떄 제곱연산자
**사용**
// bad
const binary = Math.pow(2, 10);
// good
const binary = 2 ** 10;
이미 한번 당함 (Math.pow는 실수연산이라 큰 숫자에서 오차가 생김)
변수
-
변수를 선언할 때는 항상
const와let만 사용 그렇지 않으면 전역 변수로 선언된다. 전역 스페이스를 오염시키지 않기를 바란다 -
하나의 변수 선언 / 할당에는 하나의
const나let을 사용 디버거로 선언을 단계별로 살펴볼 수 있다
// 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 을 쓰라는 뜻
// 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는 블록 스코프이지, 함수 스코프가 아님
// 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;
}
코드 윗쪽에서 사용할 변수를 전부 선언해야하는 강박에서 자유로워질수 있다
- 변수 할당 체이닝을 사용하지 않기 변수할당 체이닝은 암시 전역변수를 만든다
// 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과 같은 구문으로 값을 변경하는것이++,--구문을 사용하는것보다 의미있는 일이라고 생각된다 이것도 좀 충격적이네 -
값을 할당할 때
=앞 뒤에서 줄 바꿈하지 말기 할당하는 값의 길이가 길어질 경우 값을 괄호로 둘러싸기
// bad
const foo = superLongLongLongLongLongLongLongLongFunctionName();
// bad
const foo = 'superLongLongLongLongLongLongLongLongString';
// good
const foo = superLongLongLongLongLongLongLongLongFunctionName();
// good
const foo = 'superLongLongLongLongLongLongLongLongString';
- 사용하지 않는 변수 남겨두지 말기
호이스팅
- let과 const 는 Temporal Dead Zones (TDZ)이라고 불리는 새로운 개념의 혜택을 받음
var는 가장 가까운 함수스코프 꼭대기에 호이스팅 되는다는데 (
안쓸거니까 알 필요없다)
// (전역 변수 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;
}
- 익명 함수의 경우 함수가 할당되기 전의 변수가 호이스트 됨
function example() {
console.log(anonymous); // = undefined
anonymous(); // = TypeError anonymous is not a function
var anonymous = function () {
console.log('anonymous function expression');
};
}
- 명명 함수의 경우도 똑같이 변수가 호이스트되고, 함수의 이름이나 본체는 호이스트 되지 않음
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로 평가*
if ([0] && []) {
// true
// 배열(빈 배열 포함)은 객체이며, 객체는 참으로 평가됩니다.
}
- Boolean 비교는 단축형을 사용, 단 숫자나 문자열은 명시적으로 비교
// bad
if (isValid === true) {
// ...
}
// good
if (isValid) {
// ...
}
// bad
if (name) {
// ...
}
// good
if (name !== '') {
// ...
}
// bad
if (collection.length) {
// ...
}
이것도 좀 간과하기 쉬운 컨벤션인듯 더 자세한 내용은 Truth Equality and JavaScript
- 렉시컬 선언(
let,const,function,class) 을 포함하는switch문 안에 블록을 만들 떄 괄호 사용하기
// 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 {}
}
}
- 삼항 연산자를 중첩해서는, 안되며 일반적으로 한줄로 표현
- 불필요한 삼항 연산자는 사용하지 말기 어지간하면 삼항 연산자는 사용하는걸 피하자
// 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;
- 연산자를 섞어 사용할 때 해당 연산자들을 괄호로 둘러싸기 코드가 더 읽기쉬우지고, 개발자의 의도가 명확해짐
// 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;
블록
- 여러 줄의 블록에는 중괄호를 사용 해오던대로 하면 됨
// 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 블록의 닫는 중괄호와 같은 줄에 두기
// 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 문으로 나누어질 수 있음
// 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)이 너무 긴 경우, 각 조건을 새로운 줄에 두기. 논리 연산자는 줄의 시작부분에 와야함
// 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();
}
- 선택연산자를 제어구문대신 쓰지 말기
// bad
!isRunning && startRunning();
// good
if (!isRunning) {
startRunning();
}
주석
- **여러 줄에 걸쳐 주석을 작성할 때에는
/** … \*/을 사용하기**
// bad
// make()는 전달된 태그명을 기반으로
// 새로운 요소를 반환한다.
//
// @param {String} tag
// @return {Element} element
function make(tag) {
// ...
return element;
}
// good
/**
* make()는 전달된 태그명을 기반으로
* 새로운 요소를 반환한다.
*/
function make(tag) {
// ...
return element;
}
- 한 줄 주석을 사용 할때에는
//를 사용하기. 주석 전에는 빈행을 넣기
// 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;
}
- 모든 주석은 공백으로 시작해야함
// 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:사용
class Calculator extends Abacus {
constructor() {
super();
// FIXME: 전역 변수를 사용해서는 안 됨
total = 0;
}
}
- 문제의 해결책에 대한 주석은
// TODO:사용
class Calculator extends Abacus {
constructor() {
super();
// TODO: total은 옵션 파라메터로 설정해야함
this.total = 0;
}
}
공백
- 탭은 공백문자 두개로 작성하기 난 지금까지 4칸으로 썼는데 2칸으로 줄여야겠다
// bad
function foo() {
∙∙∙∙let name;
}
// bad
function bar() {
∙let name;
}
// good
function baz() {
∙∙let name;
}
- 주요 중괄호 앞에는 공백문자 한개 넣기
// 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) 의 소괄호 앞에는 공백 하나 넣기, 함수선언이나 호출시 인자앞 공백 넣지 말기 함수에서 사용하는 소괄호에는 공백넣지 말기 기억
// bad
if (isJedi) {
fight();
}
// good
if (isJedi) {
fight();
}
// bad
function fight() {
console.log('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
- 파일 끝에 개행문자 1개 넣기 그니까 파일 끝은 무조건 개행문자로만 끝나게 만들라는 뜻
// 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개이상) 들여쓰기를 하기, 그리고 마침표를 맨 앞에 두기
// 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);
- 구문의 앞과 블록의 뒤에는 빈 행을 두기
// 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() {
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);
}
- 여러 빈행을 두지 않기 깔끔해 보이려고 빈행을 억지로 넣지 말아라
// 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) {
// ..
}
}
-
소괄호 안쪽에 공백 두지 않기
-
대괄호 안쪽에 공백 두지 않기
// 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' };
- 한 줄에 코드가 100자 넘는것은 피하기 (공백포함) 긴문자열인 경우는 예외 (문자열 길다고 분리해서 쓰면 안됨)
// 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.'));
-
쉼표 이전에는 공백넣지말고, 이후에 공백넣기 하던대로 하면됨
-
계산된 속성 내에서는 공백을 넣으세요
// 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”을 사용하라는 뜻인듯 싶다
- 함수 호출할떄 공백 넣지 말기
- 객체 리터럴 속성의 키와 값 사이에는 공백 넣기
// bad
var obj = { foo: 42 };
var obj2 = { foo: 42 };
// good
var obj = { foo: 42 };
- 행의 마지막에 공백 남겨놓지 말기
- 여러 빈행을 쓰지 말기, 파일의 맨앞에 빈행 쓰지 말기 파일 끝에는 마지막행에는 빈행 하나두기
// 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) 뒤에는 쉼표가 없다
// 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 붙이지 말기
// = 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)를 사용하라는 뜻
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) 주석으로 남겨라
// 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비트 이상 넘어가면 예기치못한 현상을 야기할수 있음
2147483647 0; // = 2147483647
2147483648 0; // = -2147483648
2147483649 0; // = -2147483647
- 불리언
const age = 0;
// bad
const hasAge = new Boolean(age);
// good
const hasAge = Boolean(age);
// best
const hasAge = !!age;
명명 규칙
- 한 문자로 된 이름은 피해라 이름으로부터 의도가 읽혀질수 있도록 해라
// bad
function q() {
// ...
}
// good
function query() {
// ...
}
- 객체, 함수, 인스턴스에는 캐멀케이스(camelCase)를 사용
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
- 클래스나 생성자에는 파스칼케이스(PascalCase)를 사용
// 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하게 사용하고싶다면, 그것을 불가능하다
// 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 사용
// 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의 이름과 일치해야한다
// 파일 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하는 객체의 경우는 파스칼케이스로 쓰라한다 / 일반적으로는 캐멀케이스
const AirbnbStyleGuide = {
es6: {},
};
export default AirbnbStyleGuide;
- 두 문자어나 이니셜은 모두 대문자거나 소문자여야 함 이름은 가독성을 위한것이지, 컴퓨터 알고리즘을 위한 것이 아니다
// 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) 모든 중첩된 속성이 변경되지 않도록 유지합니다.
// 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를 사용하지 마라 예기치 못한 사이드이펙트를 일으키고, 테스트와 유지보수를 힘들게 한다
// bad
class Dragon {
get age() {
// ...
}
set age(value) {
// ...
}
}
// good
class Dragon {
getAge() {
// ...
}
setAge(value) {
// ...
}
}
- 속성이나 메소드가
boolean이라면,isVal이나hasVal을 사용
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
- get(), set() 함수를 만들되, 일관성있게 만들기
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의 값을 추가할 수 있다.
// 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
});
제이쿼리
- 제이쿼리 객체 변수 앞에
$를 붙여라
// bad
const sidebar = $('.sidebar');
// good
const $sidebar = $('.sidebar');
// good
const $sidebarBtn = $('.sidebar-btn');
- 제이쿼리의 검색결과 를 캐시 쓸 때마다 호출해서 찾지말고, 찾은값을 변수에 담아놓으라는 뜻
// 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사용
// bad
$('ul', '.sidebar').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar ul').hide();
// good
$sidebar.find('ul').hide();