자바 스크립트에 대한 가장 합리적인 접근 방식

다른 스타일 가이드들
- 유형(Types)
- 참조(References)
- 객체(Objects)
- 배열(Arrays)
- 구조화 대입(Destructuring)
- 문자열(Strings)
- 함수(Functions)
- 애로우 함수(Arrow Functions)
- 생성자(Constructors)
- 모듈(Modules)
- 이터레이터와 제너레이터(Iterators and Generators)
- 속성(Properties)
- 변수(Variables)
- 호이스팅(Hoisting)
- 조건식과 등가현(Comparison Operators & Equality)
- 블록(Blocks)
- 주석(Comments)
- 공백(Whitespace)
- 쉼표(Commas)
- 세미콜론(Semicolons)
- 형변환과 강제(Type Casting & Coercion)
- 명명 규칙(Naming Conventions)
- 액세서(Accessors)
- 이벤트(Events)
- jQuery
- ECMAScript 5 호환성(ECMAScript 5 Compatibility)
- ECMAScript 6 스타일(ECMAScript 6 Styles)
- 테스팅(Testing)
- 성능(Performance)
- 참고(Resources)
- 기여(In the Wild)
- 번역(Translation)
- 자바스크립트 스타일 가이드 안내서(The JavaScript Style Guide Guide)
- 자바스크립트 스타일 가이드 채팅(Chat With Us About JavaScript)
- 참여자(Contributors)
- 라이센스(License)
-
1.1 Primitives: 원시형(Primitive type)은 그 값을 직접 조작합니다.
string
number
boolean
null
undefined
const foo = 1; let bar = foo; bar = 9; console.log(foo, bar); // => 1, 9
-
1.2 Complex: 참조형(Complex type)은 참조를 통해 값을 조작합니다.
object
array
function
const foo = [1, 2]; const bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // => 9, 9
-
2.1 모든 참조에는
const
를 사용하고var
를 사용하지 않습니다.왜죠? 참조를 다시 할당할 수 없어서, 버그로 연결되거나 이해하기 어려운 코드가 되는 것을 예방합니다.
eslint rules:
prefer-const
,no-const-assign
.// bad var a = 1; var b = 2; // good const a = 1; const b = 2;
-
2.2 참조를 다시 할당해야 하는 경우
var
대신에let
을 사용하세요.왜죠?
var
는 함수-범위(function-scoped)이고let
은 블록-범위(block-scoped)이기 때문입니다.eslint rules:
no-var
.// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }
-
2.3
let
과const
는 모두 블록-범위(block-scoped)인 것에 주의해야 합니다.// const와 let은 선언 된 블록 안에서만 존재함. { let a = 1; const b = 1; } console.log(a); // ReferenceError console.log(b); // ReferenceError
-
3.1 객체를 만들 때에는 리터럴 구문을 사용합니다.
eslint rules:
no-new-object
.// bad const item = new Object(); // good const item = {};
-
3.2 코드가 브라우저에서 실행되는 경우 예약어를 키로 사용하지 마세요. 이것은 IE8에서 작동하지 않습니다. 더 알아보기. ES6 모듈과 서버 사이드에서는 사용할 수 있습니다.
// bad const superman = { default: { clark: 'kent' }, private: true, }; // good const superman = { defaults: { clark: 'kent' }, hidden: true, };
-
3.3 예약어 대신에 알기 쉬운 동의어(Readable Synonyms)를 사용하세요.
// bad const superman = { class: 'alien', }; // bad const superman = { klass: 'alien', }; // good const superman = { type: 'alien', };
-
3.4 동적인 속성 이름을 가진 객체를 만들 때에는 계산된 속성 이름(Computed Property Names)을 사용하세요.
왜죠? 이렇게하면 객체 속성을 한 개의 장소에서 정의 할 수 있습니다.
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, };
-
3.5 메소드에 단축 구문(Object Shorthand)을 사용하세요.
eslint rules:
object-shorthand
.// bad const atom = { value: 1, addValue: function (value) { return atom.value + value; }, }; // good const atom = { value: 1, addValue(value) { return atom.value + value; }, };
-
3.6 속성에 단축 구문(Object Concise)을 사용하세요.
왜죠? 표현이나 설명이 간결해지기 때문입니다.
eslint rules:
object-shorthand
.const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, };
-
3.7 속성의 단축 구문(Object Concise)은 객체 선언의 시작 부분에 무리를 지어줍니다.
왜죠? 어떤 속성이 단축 구문을 사용하고 있는지를 알기가 쉽기 때문입니다.
const anakinSkywalker = 'Anakin Skywalker'; const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { episodeOne: 1, twoJediWalkIntoACantina: 2, lukeSkywalker, episodeThree: 3, mayTheFourth: 4, anakinSkywalker, }; // good const obj = { lukeSkywalker, anakinSkywalker, episodeOne: 1, twoJediWalkIntoACantina: 2, episodeThree: 3, mayTheFourth: 4, };
-
3.8 속성 이름에 작은 따옴표를 사용하는 경우는 오직 잘못된 식별자(Invalid Identifiers)일 때입니다.
왜죠? 주관적으로 쉽게 읽을 수 있는 것을 항상 고민해야 합니다. 이 것은 구문이 강조되고, 수많은 JS엔진에 쉽게 최적화되어 있습니다.
eslint rules: quote-props
.
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
};
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
};
-
4.1 배열을 만들 때 리터럴 구문을 사용하세요.
eslint rules:
no-array-constructor
.// bad const items = new Array(); // good const items = [];
-
4.2 배열에 항목을 직접 대체하지 말고 Array#push를 사용하세요.
const someStack = []; // bad someStack[someStack.length] = 'abracadabra'; // good someStack.push('abracadabra');
-
4.3 배열을 복사하는 경우, 배열의 확장 연산자인
...
을 사용하세요.// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
-
4.4 Array-Like 객체를 배열로 변환하려면 Array#from을 사용하세요.
const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo);
-
5.1 여러 속성에서 객체에 접근할 때 객체 구조화 대입(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.2 배열에 구조화 대입(Destructuring)을 사용하세요.
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
-
5.3 여러 값을 반환하는 경우, 배열의 구조화 대입이 아니라 객체의 구조화 대입을 사용하세요.
왜죠? 이렇게하면 나중에 새 속성을 추가하거나 호출에 영향을 주지않고 순서를 변경할 수 있습니다.
// 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, right } = processInput(input);
-
6.1 문자열에는 작은 따옴표
''
를 사용하세요.eslint rules:
quotes
.// bad const name = "Capt. Janeway"; // good const name = 'Capt. Janeway';
-
6.2 100자 이상의 문자열은 여러 행을 사용하여 연결할 수 있습니다.
-
6.3 주의: 문자열 연결이 많으면 성능에 영향을 줄 수 있습니다. jsPerf & Discussion.
// 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.4 프로그램에서 문자열을 생성하는 경우, 문자열 연결이 아니라 템플릿 문자열(Template Strings)을 사용하세요.
왜죠? 템플릿 문자열의 문자열 완성 기능과 다중 문자열 기능을 가진 간결한 구문으로 가독성이 좋아지기 때문입니다.
eslint rules:
prefer-template
.// 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}?`; }
-
6.5 절대로
eval()
을 사용하지 않습니다. 이것은 지금까지 수많은 취약점을 만들어 왔기 때문입니다.
-
7.1 함수 선언 대신에 함수 표현식을 사용합니다.
왜죠? 이름이 붙은 함수 선언은 콜스택에서 쉽게 알수 있습니다. 또한 함수 선언의 몸 전체가 Hoist됩니다. 반면 함수는 참조만 Hoist됩니다. 이 규칙은 함수 부분을 항상 애로우 함수로 대체 사용할 수 있습니다.
// bad const foo = function () { }; // good function foo() { }
-
7.2 함수 표현식(Function expressions):
// 즉시-호출(Immediately-Invoked) 함수 표현식(IIFE) (() => { console.log('Welcome to the Internet. Please follow me.'); })();
-
7.3 함수 이외의 블록 (
if
나while
등)에 함수를 선언하지 않습니다. 브라우저는 변수에 함수를 할당하는 처리를 할 수는 있지만, 모두 다르게 해석됩니다. -
7.4 주의: ECMA-262에서
block
은 statements 목록에 정의되지만, 함수 선언은 statements가 없습니다. 이 문제는 ECMA-262의 설명을 참조하세요.// bad if (currentUser) { function test() { console.log('Nope.'); } } // good let test; if (currentUser) { test = () => { console.log('Yup.'); }; }
-
7.5 매개변수(parameter)에
arguments
를 절대로 지정하지 않습니다. 이것은 함수 영역으로 전달 될arguments
객체의 참조를 덮어 써버릴 것입니다.// bad function nope(name, options, arguments) { // ...stuff... } // good function yup(name, options, args) { // ...stuff... }
-
7.6
arguments
를 사용하지 않습니다. 대신 레스트(Rest) 문법인...
을 사용하세요.왜죠?
...
를 이용하여 여러가지 매개변수를 모두 사용할 수 있습니다. 추가로 rest 매개변수인arguments
는 Array-Like 객체가 아니라 진정한 배열(Array)입니다.// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
-
7.7 함수의 매개변수를 조작하지 말고 기본 매개변수(Default Parameters)를 사용하세요.
// really bad function handleThings(opts) { // 안되! 함수의 매개변수를 조작하지 않습니다. // 만약 opts가 falsy 인 경우는 바란대로 객체가 설정됩니다. // 그러나 미묘한 버그를 일으키는 원인이 될수도 있습니다. opts = opts || {}; // ... } // still bad function handleThings(opts) { if (opts === void 0) { opts = {}; } // ... } // good function handleThings(opts = {}) { // ... }
-
7.8 부작용이 있는 기본 매개변수를 사용하지 않습니다.
왜죠? 혼란스럽기 때문입니다.
var b = 1; // bad function count(a = b++) { console.log(a); } count(); // 1 count(); // 2 count(3); // 3 count(); // 3
-
7.9 항상 기본 매개변수는 앞쪽에 배치하세요.
// bad function handleThings(opts = {}, name) { // ... } // good function handleThings(name, opts = {}) { // ... }
-
7.10 새로운 함수를 만드는 데 Function 생성자를 사용하지 않습니다.
왜죠? 이 방법은 문자열을 구분하는 새로운 함수를 만들 수 있는 eval()과 같은 취약점이 발생할 수 있습니다.
// bad var add = new Function('a', 'b', 'return a + b'); // still bad var subtract = Function('a', 'b', 'return a - b');
-
7.11 함수에 사용되는 공백
왜죠? 일관성이 좋고, 함수이름을 추가 하거나 삭제할 때 공백을 제거할 필요가 없습니다.
// bad const f = function(){}; const g = function (){}; const h = function() {}; // good const x = function () {}; const y = function a() {};
-
7.12 절대로 매개변수를 조작하지 않습니다.
왜죠? 매개변수로 전달 된 객체를 조작하는 것은 원래의 호출에 원치 않는 변수 부작용을 일으킬 수 있습니다.
eslint rules:
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 절대로 매개변수를 다시 지정하지 않습니다.
왜죠?
arguments
객체에 접근하는 경우 다시 지정된 매개변수는 예기치 않은 동작이 발생할 수 있습니다. 그리고 특히 V8 최적화에 문제가 발생할 수 있습니다.eslint rules:
no-param-reassign
.// 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) { }
-
8.1 함수 표현식을 사용하는 경우(익명 함수와 같은), 애로우 함수(Arrow Functions)를 사용하세요.
왜죠? 애로우 함수는 함수가 실행되는 컨텍스트의
this
를 가두어줍니다. 이것은 너무나 원했던 것이며 구문도 더욱 간결해집니다.언제 쓰죠? 복잡한 함수 논리를 정의한 함수의 바깥쪽으로 이동하고 싶은 경우입니다.
eslint rules:
prefer-arrow-callback
,arrow-spacing
.// 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을 사용할 수 있습니다. 그렇지 않으면return
문을 사용해야 합니다.왜죠? 가독성이 좋아지기 때문입니다. 여러 함수가 연결되는 경우에 쉽게 읽을 수 있습니다.
언제 쓰죠? 객체를 반환하는 경우.
eslint rules:
arrow-parens
,arrow-body-style
.// good [1, 2, 3].map(number => `A string containing the ${number}.`); // bad [1, 2, 3].map(number => { const nextNumber = number + 1; `A string containing the ${nextNumber}.`; }); // good [1, 2, 3].map(number => { const nextNumber = number + 1; return `A string containing the ${nextNumber}.`; });
-
8.3 구문의 길이가 여러 행에 걸치는 경우 가독성을 향상시키기 위해 괄호
()
안에 써주세요.왜죠? 함수의 시작과 끝 부분을 알아보기 쉽게 합니다.
// bad [1, 2, 3].map(number => 'As time went by, the string containing the ' + `${number} became much longer. So we needed to break it over multiple ` + 'lines.' ); // good [1, 2, 3].map(number => ( `As time went by, the string containing the ${number} became much ` + 'longer. So we needed to break it over multiple lines.' ));
-
8.4 함수의 인수가 한 개인 경우 괄호
()
를 생략할 수 있습니다.왜죠? 시각적 혼란이 덜하기 때문입니다.
eslint rules:
arrow-parens
.// bad [1, 2, 3].map((x) => x * x); // good [1, 2, 3].map(x => x * x); // good [1, 2, 3].map(number => ( `A long string with the ${number}. It’s so long that we’ve broken it ` + 'over multiple lines!' )); // 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; });
-
9.1
prototype
의 직접 조작을 피하고 항상class
를 사용하세요.왜죠?
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; } }
-
9.2 상속은
extends
를 사용하세요.왜죠? 프로토타입을 상속하기 위해 내장된 방식으로
instanceof
를 파괴할 수 없기 때문입니다.// 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.3 메소드의 반환 값에
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);
-
9.4 사용자화 된 toString() 메소드를 쓰는 것도 좋습니다. 단, 제대로 작동하는지, 부작용이 없는 지를 꼭 확인하세요.
class Jedi { constructor(options = {}) { this.name = options.name || 'no name'; } getName() { return this.name; } toString() { return `Jedi - ${this.getName()}`; } }
-
10.1 비표준 모듈 시스템이 아니라면 항상 (
import
/export
) 를 사용하세요. 이렇게 함으로써 원하는 모듈 시스템에 언제든지 트랜스파일(Transpile) 할 수 있습니다.왜죠? 모듈은 곧 미래입니다. 미래를 선점하고 애용합시다.
// 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.2 와일드카드를 이용한 가져오기는 사용하지 않습니다.
왜죠? single default export인 것에 주의할 필요가 있기 때문입니다.
// bad import * as AirbnbStyleGuide from './AirbnbStyleGuide'; // good import AirbnbStyleGuide from './AirbnbStyleGuide';
-
10.3 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;
-
11.1 이터레이터(Iterators)를 사용하지 않습니다.
for-of
루프 대신map()
과reduce()
같은 자바스크립트의 고급함수(higher-order functions)를 사용하세요.왜죠? 이것은 불변(Immutable)의 규칙을 적용합니다. 값을 반환하는 함수를 처리하는 것이 부작용을 예측하기가 더 쉽습니다.
eslint rules:
no-iterator
.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;
-
11.2 현재 제너레이터(Generators)는 사용하지 않는 것이 좋습니다.
왜죠? ES5에서 트랜스파일(Transpile)이 올바로 작동하지 않습니다.
-
12.1 속성에 접근하려면 점
.
을 사용하세요.eslint rules:
dot-notation
.const luke = { jedi: true, age: 28, }; // bad const isJedi = luke['jedi']; // good const isJedi = luke.jedi;
-
12.2 변수를 사용하여 속성에 접근하려면 대괄호
[]
를 사용하세요.const luke = { jedi: true, age: 28, }; function getProp(prop) { return luke[prop]; } const isJedi = getProp('jedi');
-
13.1 변수를 선언 할 때는 항상
const
를 사용하세요. 그렇지 않을 경우 전역 변수로 선언됩니다. 글로벌 네임 스페이스가 오염되지 않도록 캡틴 플래닛(역자주: 환경보호와 생태를 테마로 한 슈퍼히어로 애니메이션)도 경고하고 있습니다.// bad superPower = new SuperPower(); // good const superPower = new SuperPower();
-
13.2 하나의 변수 선언에 대해 하나의
const
를 사용하세요.왜죠? 이 방법은 새로운 변수를 쉽게 추가할 수 있습니다. 또한 구분 기호의 차이에 의한
;
을,
로 다시금 대체하는 작업에 대해 신경쓸 필요가 없습니다.eslint rules:
one-var
.// bad const items = getItems(), goSportsTeam = true, dragonball = 'z'; // bad // (compare to above, and try to spot the mistake) const items = getItems(), goSportsTeam = true; dragonball = 'z'; // good const items = getItems(); const goSportsTeam = true; const dragonball = 'z';
-
13.3 먼저
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;
-
13.4 변수를 할당을 필요로 하는 부분에서 적당한 장소에 배치해야 합니다.
왜죠?
let
과const
는 함수 범위에는 없는 블록 범위이기 때문입니다.// good function () { test(); console.log('doing stuff..'); //..other stuff.. const name = getName(); if (name === 'test') { return false; } return name; } // bad - unnecessary function call function (hasName) { const name = getName(); if (!hasName) { return false; } this.setFirstName(name); return true; } // good function (hasName) { if (!hasName) { return false; } const name = getName(); this.setFirstName(name); return true; }
-
14.1
var
선언은 할당이 없는 상태로 범위(Scope)의 위로 Hoist될 수 있습니다. 하지만const
와let
선언은 시간적 데드 존(Temporal Dead Zones (TDZ))이라는 새로운 개념의 혜택을 받고 있습니다. 이것은 왜 typeof가 안전하지 않은가(typeof is no longer safe)를 알고있는 것이 중요합니다.// (notDefined가 글로벌 변수에 존재하지 않는다고 가정했을 경우) // 이것은 잘 작동하지 않습니다. function example() { console.log(notDefined); // => throws a ReferenceError } // 변수를 참조하는 코드 후에 그 변수를 선언한 경우 // 변수가 Hoist되어서 작동합니다. // 주의: `true` 값 자체는 Hoist할 수 없습니다. function example() { console.log(declaredButNotAssigned); // => undefined var declaredButNotAssigned = true; } // 인터프린터는 변수 선언을 범위(Scope)의 시작부분에 Hoist합니다. // 위의 예는 다음과 같이 다시 작성할 수 있습니다: 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; }
-
14.2 익명 함수 표현식에서는 함수가 할당되기 전에 변수가 Hoist될 수 있습니다.
function example() { console.log(anonymous); // => undefined anonymous(); // => TypeError anonymous is not a function var anonymous = function () { console.log('anonymous function expression'); }; }
-
14.3 명명된 함수의 경우도 마찬가지로 변수가 Hoist될 수 있습니다. 함수이름과 함수본문는 Hoist되지 않습니다.
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'); } }
-
14.4 함수 선언은 함수이름과 함수본문이 Hoist됩니다.
function example() { superPower(); // => Flying function superPower() { console.log('Flying'); } }
-
더 자세한 정보는 Ben Cherry의 JavaScript Scoping & Hoisting을 참조하세요.
-
15.1
==
와!=
보다는===
와!==
를 사용하세요. -
15.2
if
와 같은 조건문은ToBoolean
방법에 의한 강제 형(Type) 변환으로 구분되고 항상 다음과 같은 간단한 규칙을 따릅니다:eslint rules:
eqeqeq
.- Objects는 true로 구분됩니다.
- Undefined는 false로 구분됩니다.
- Null은 false로 구분됩니다.
- Booleans은 boolean형의 값으로 구분됩니다.
- Numbers는 true로 구분됩니다. 그러나, +0, -0, 또는 NaN인 경우 false로 구분됩니다.
- Strings는 true로 구분됩니다. 그러나, 비어있는
''
경우는 false로 구분됩니다.
if ([0]) { // true // 배열은 객체이므로 true로 구분됩니다. }
-
15.3 손쉬운 방법을 사용하세요.
// bad if (name !== '') { // ...stuff... } // good if (name) { // ...stuff... } // bad if (collection.length > 0) { // ...stuff... } // good if (collection.length) { // ...stuff... }
-
15.4 더 자세한 내용은 여기를 참조하세요. Truth Equality and JavaScript by Angus Croll.
-
16.1 여러 줄의 블록은 중괄호
{}
를 사용합니다.// bad if (test) return false; // good if (test) return false; // good if (test) { return false; } // bad function () { return false; } // good function () { return false; }
-
16.2 여러 블록에 걸친
if
와else
를 사용하는 경우,else
는if
블록의 끝 중괄호{}
와 같은 행에 두세요.eslint rules:
brace-style
.// bad if (test) { thing1(); thing2(); } else { thing3(); } // good if (test) { thing1(); thing2(); } else { thing3(); }
-
17.1 여러 줄의 주석에는
/** ... */
를 사용하세요. 그 안에는 설명과 모든 매개변수와 반환 값에 대한 형식과 값을 표기합니다.// bad // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element function make(tag) { // ...stuff... return element; } // good /** * make() returns a new element * based on the passed in tag name * * @param {String} tag * @return {Element} element */ function make(tag) { // ...stuff... return element; }
-
17.2 한 줄 주석에는
//
를 사용하세요. 주석을 추가하싶은 코드의 상단에 배치하세요. 또한 주석 앞에 빈 줄을 넣어주세요.// 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; }
-
17.3 문제를 지적하고 재고를 촉구하거나 문제의 해결책을 제시하는 경우 등, 주석 앞에
FIXME
또는TODO
를 붙이는 것으로 다른 개발자의 빠른 이해를 도울 수 있습니다. 이들은 어떠한 액션을 따른다는 의미에서 일반 댓글과 다를 수 있습니다. 액션은FIXME -- 해결책 필요
또는TODO -- 구현 필요
. -
17.4 문제에 대한 주석으로
// FIXME:
를 사용하세요.class Calculator extends Abacus { constructor() { super(); // FIXME: shouldn't use a global here total = 0; } }
-
17.5 해결책에 대한 주석으로
// TODO:
를 사용하세요.class Calculator extends Abacus { constructor() { super(); // TODO: total should be configurable by an options param this.total = 0; } }
-
18.1 탭에 공백 2개를 설정하세요.
eslint rules:
indent
.// bad function () { ∙∙∙∙const name; } // bad function () { ∙const name; } // good function () { ∙∙const name; }
-
18.2 중괄호
{}
앞에 공백을 넣어주세요.eslint rules:
space-before-blocks
.// 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', });
-
18.3 제어 구문(
if
,while
등)의 괄호()
앞에 공백을 넣어주세요. 함수 선언과 함수 호출시 인수 목록 앞에는 공백을 넣지 않습니다.eslint rules:
space-after-keywords
,space-before-keywords
.// bad if(isJedi) { fight (); } // good if (isJedi) { fight(); } // bad function fight () { console.log ('Swooosh!'); } // good function fight() { console.log('Swooosh!'); }
-
18.4 연산자 사이에는 공백이 있습니다.
eslint rules:
space-infix-ops
.// bad const x=y+5; // good const x = y + 5;
-
18.5 파일의 마지막에 빈 줄을 하나 넣어주세요.
// bad (function (global) { // ...stuff... })(this);
// bad (function (global) { // ...stuff... })(this);↵ ↵
// good (function (global) { // ...stuff... })(this);↵
-
18.6 메소드 체인이 길어지는 경우 적절히 들여쓰기(indentation) 하세요. 행이 메소드 호출이 아닌 새로운 문장임을 강조하기 위해 선두에 점
.
을 배치하세요.// 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').class('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);
-
18.7 블록과 다음 Statement 사이에 빈 줄을 넣어주세요.
// 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;
-
18.8 블록에 빈 줄을 끼워넣지 않습니다.
eslint rules:
padded-blocks
.// bad function bar() { console.log(foo); } // also bad if (baz) { console.log(qux); } else { console.log(foo); } // good function bar() { console.log(foo); } // good if (baz) { console.log(qux); } else { console.log(foo); }
-
18.9 괄호
()
안에 공백을 추가하지 않습니다.eslint rules:
space-in-parens
.// bad function bar( foo ) { return foo; } // good function bar(foo) { return foo; } // bad if ( foo ) { console.log(foo); } // good if (foo) { console.log(foo); }
-
18.10 대괄호
[]
안에 공백을 추가하지 않습니다.eslint rules:
array-bracket-spacing
.// bad const foo = [ 1, 2, 3 ]; console.log(foo[ 0 ]); // good const foo = [1, 2, 3]; console.log(foo[0]);
-
18.11 중괄호
{}
안에 공백을 추가하지 않습니다.eslint rules:
object-curly-spacing
.// bad const foo = {clark: 'kent'}; // good const foo = { clark: 'kent' };
-
18.12 한 줄에 100문자(공백 포함)가 넘는 코드는 피하세요.
왜죠? 가독성과 유지 보수성을 보장합니다.
eslint rules:
max-len
.// bad const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. Whatever wizard constrains a helpful ally. The counterpart ascends!'; // 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 = 'Whatever national crop flips the window. The cartoon reverts within the screw. ' + 'Whatever wizard constrains a helpful ally. The counterpart ascends!'; // good $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' }, }) .done(() => console.log('Congratulations!')) .fail(() => console.log('You have failed this city.'));
-
19.1 쉼표로 시작: 제발 그만하세요.
eslint rules:
comma-style
.// 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', };
-
19.2 마지막에 쉼표: 좋습니다.
eslint rules:
comma-dangle
.왜죠? 이것은 git의 diff를 깨끗하게 합니다. 또한 Babel과 같은 트랜스 컴파일러는 끝에 불필요한 쉼표를 알아서 제거합니다. 이것은 기존 브라우저에서 불필요한 쉼표 문제를 걱정할 필요가 없다는 것을 의미합니다.
// bad - git diff without trailing comma const hero = { firstName: 'Florence', - lastName: 'Nightingale' + lastName: 'Nightingale', + inventorOf: ['coxcomb graph', 'modern nursing'] }; // good - git diff with trailing comma const hero = { firstName: 'Florence', lastName: 'Nightingale', + inventorOf: ['coxcomb chart', 'modern nursing'], }; // bad const hero = { firstName: 'Dana', lastName: 'Scully' }; const heroes = [ 'Batman', 'Superman' ]; // good const hero = { firstName: 'Dana', lastName: 'Scully', }; const heroes = [ 'Batman', 'Superman', ];
-
20.1 물론 사용합시다.
eslint rules:
semi
.// bad (function () { const name = 'Skywalker' return name })() // good (() => { const name = 'Skywalker'; return name; })(); // good (guards against the function becoming an argument when two files with IIFEs are concatenated) ;(() => { const name = 'Skywalker'; return name; })();
-
21.1 문장의 시작 부분에서 형(Type)을 강제합니다.
-
21.2 String:
// => this.reviewScore = 9; // bad const totalScore = this.reviewScore + ''; // good const totalScore = String(this.reviewScore);
-
21.3 Number:
Number
형으로 변환하려면parseInt
를 사용하세요. 항상 형변환을 위한 기수(radix)를 인수로 전달합니다.eslint rules:
radix
.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);
-
21.4 어떤 이유로
parseInt
가 병목이되고, 성능적인 이유에서 Bitshift를 사용해야 하는 경우, 무엇을(what) 왜(why)에 대한 설명을 댓글로 남겨 주세요.// good /** * parseInt가 병목이되고 있었기 때문에, * Bitshift 문자열을 수치로 강제로 변환하여 * 성능을 향상시킵니다. */ const val = inputValue >> 0;
-
21.5 주의: Bitshift를 사용하는 경우 수치는 64-비트 값들로 표현되어 있지만, Bitshift를 연산하면 항상 32-비트 단 정밀도로 돌려 주어집니다(source). 32-비트 이상의 값을 비트 이동하면 예상치 못한 행동을 일으킬 가능성이 있습니다. Discussion. 부호있는 32-비트 정수의 최대 값은 2,147,483,647입니다:
2147483647 >> 0 //=> 2147483647 2147483648 >> 0 //=> -2147483648 2147483649 >> 0 //=> -2147483647
-
21.6 Booleans:
const age = 0; // bad const hasAge = new Boolean(age); // good const hasAge = Boolean(age); // good const hasAge = !!age;
-
22.1 하나의 문자로 구성된 이름은 피하세요. 이름에서 의도를 읽을 수 있도록 해야 합니다.
// bad function q() { // ...stuff... } // good function query() { // ..stuff.. }
-
22.2 객체, 함수 인스턴스에는 camelCase(소문자로 시작)를 사용하세요.
eslint rules:
camelcase
.// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
-
22.3 클래스와 생성자는 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', });
-
22.4 Private 속성 이름은 앞에 밑줄
_
을 사용하세요.eslint rules:
no-underscore-dangle
.// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; // good this._firstName = 'Panda';
-
22.5
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); }; }
-
22.6 파일을 하나의 클래스로 추출(Export)할 경우 파일 이름은 클래스 이름과 정확하게 일치해야 합니다.
// file contents class CheckBox { // ... } export default CheckBox; // in some other file // bad import CheckBox from './checkBox'; // bad import CheckBox from './check_box'; // good import CheckBox from './CheckBox';
-
22.7 export-default 함수의 경우, camelCase(소문자로 시작)를 사용하세요. 파일이름은 함수이름과 동일해야 합니다.
function makeStyleGuide() { } export default makeStyleGuide;
-
22.8 싱글톤(singleton) / 함수 라이브러리(function library) / 단순한 객체(bare object)를 추출하는 경우, PascalCase(대문자로 시작)를 사용하세요.
const AirbnbStyleGuide = { es6: { } }; export default AirbnbStyleGuide;
-
23.1 속성에 대한 접근자(Accessor) 함수는 필요하지 않습니다.
-
23.2 접근자 함수가 필요한 경우
getVal()
과setVal('hello')
로 하세요.// bad dragon.age(); // good dragon.getAge(); // bad dragon.age(25); // good dragon.setAge(25);
-
23.3 속성이
boolean
의 경우isVal()
또는hasVal()
로 하세요.// bad if (!dragon.age()) { return false; } // good if (!dragon.hasAge()) { return false; }
-
23.4 일관된다면,
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]; } }
-
24.1 (DOM 이벤트, Backbone 이벤트)처럼 자신의 이벤트 페이로드 값을 전달하려면 원시값 대신 해시인수를 전달합니다. 이렇게 하면 나중에 개발자가 이벤트에 관련된 모든 핸들러를 찾아 업데이트하지 않고 이벤트 페이로드에 값을 추가할 수 있습니다. 예를 들면:
// bad $(this).trigger('listingUpdated', listing.id); ... $(this).on('listingUpdated', function (e, listingId) { // do something with listingId });
보다 아래쪽이 더 선호됨:
// good $(this).trigger('listingUpdated', { listingId: listing.id }); ... $(this).on('listingUpdated', function (e, data) { // do something with data.listingId });
-
25.1 jQuery 객체 변수 앞에는
$
로 구분합니다.// bad const sidebar = $('.sidebar'); // good const $sidebar = $('.sidebar'); // good const $sidebarBtn = $('.sidebar-btn');
-
25.2 jQuery의 검색 결과를 캐시합니다.
// bad function setSidebar() { $('.sidebar').hide(); // ...stuff... $('.sidebar').css({ 'background-color': 'pink' }); } // good function setSidebar() { const $sidebar = $('.sidebar'); $sidebar.hide(); // ...stuff... $sidebar.css({ 'background-color': 'pink' }); }
-
25.3 DOM의 검색에는
$('.sidebar ul')
또는$('.sidebar > ul')
과 같은 Cascading을 사용하세요. jsPerf -
25.4 jQuery 객체의 검색에는 범위가있는
find
를 사용하세요.// bad $('ul', '.sidebar').hide(); // bad $('.sidebar').find('ul').hide(); // good $('.sidebar ul').hide(); // good $('.sidebar > ul').hide(); // good $sidebar.find('ul').hide();
- 27.1 이것은 ES6 명세 링크를 모아 놓은 것입니다.
- 애로우 함수(Arrow Functions)
- 클래스(Classes)
- 객체 단축 구문(Object Shorthand)
- 속성 단축 구문(Object Concise)
- 계산된 속성 이름(Object Computed Properties)
- 템플릿 문자열(Template Strings)
- 구조화 대입(Destructuring)
- 기본 매개변수(Default Parameters)
- 레스트(Rest)
- 배열 스프레드(Array Spreads)
- Let과 Const(Let and Const)
- 이터레이터와 제너레이터(Iterators and Generators)
- 모듈(Modules)
-
28.1 물론 해야 합니다.
function () { return true; }
-
28.2 물론 심각하게:
-
대부분 테스트 프레임워크를 이용하여 테스트를 작성합니다.
-
작은 기능의 함수를 자주 쓰고 이변이 발생할 수 있는 부분을 최소화하기 위해 노력합니다.
-
stubs와 mocks에 주의하세요. 이 것들로 인해 테스트가 깨지기 쉽습니다.
-
지금은 달성할 필요가 없어도 100%의 테스트 커버리지를 목표로하는 것이 좋습니다.
-
버그를 수정할 때 마다 회귀 테스트를 씁니다. 회귀 테스트 없는 버그 수정은 나중에 반드시 다시 출현할 것입니다.
- On Layout & Web Performance
- String vs Array Concat
- Try/Catch Cost In a Loop
- Bang Function
- jQuery Find vs Context, Selector
- innerHTML vs textContent for script text
- Long String Concatenation
- Loading...
Learning ES6
- Draft ECMA 2015 (ES6) Spec
- ExploringJS
- ES6 Compatibility Table
- Comprehensive Overview of ES6 Features
Read This
Tools
- Code Style Linters
Other Style Guides
- Google JavaScript Style Guide
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
Other Styles
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks - Ross Allen
- Popular JavaScript Coding Conventions on Github - JeongHoon Byun
- Multiple var statements in JavaScript, not superfluous - Ben Alman
Further Reading
- Understanding JavaScript Closures - Angus Croll
- Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
- You Might Not Need jQuery - Zack Bloom & Adam Schwartz
- ES6 Features - Luke Hoban
- Frontend Guidelines - Benjamin De Cock
Books
- JavaScript: The Good Parts - Douglas Crockford
- JavaScript Patterns - Stoyan Stefanov
- Pro JavaScript Design Patterns - Ross Harmes and Dustin Diaz
- High Performance Web Sites: Essential Knowledge for Front-End Engineers - Steve Souders
- Maintainable JavaScript - Nicholas C. Zakas
- JavaScript Web Applications - Alex MacCaw
- Pro JavaScript Techniques - John Resig
- Smashing Node.js: JavaScript Everywhere - Guillermo Rauch
- Secrets of the JavaScript Ninja - John Resig and Bear Bibeault
- Human JavaScript - Henrik Joreteg
- Superhero.js - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- JSBooks - Julien Bouquillon
- Third Party JavaScript - Ben Vinegar and Anton Kovalyov
- Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript - David Herman
- Eloquent JavaScript - Marijn Haverbeke
- You Don't Know JS: ES6 & Beyond - Kyle Simpson
Blogs
- DailyJS
- JavaScript Weekly
- JavaScript, JavaScript...
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- Dustin Diaz
- nettuts
Podcasts
이 것은 본 스타일 가이드를 사용하는 조직의 목록입니다. 이 목록에 추가하고 싶다면, pull request를 하거나 issue를 통해 알려주세요.
- Aan Zee: AanZee/javascript
- Adult Swim: adult-swim/javascript
- Airbnb: airbnb/javascript
- Apartmint: apartmint/javascript
- Avalara: avalara/javascript
- Billabong: billabong/javascript
- Bisk: bisk/javascript
- Blendle: blendle/javascript
- ComparaOnline: comparaonline/javascript
- Compass Learning: compasslearning/javascript-style-guide
- DailyMotion: dailymotion/javascript
- Digitpaint digitpaint/javascript
- Ecosia: ecosia/javascript
- Evernote: evernote/javascript-style-guide
- Evolution Gaming: evolution-gaming/javascript
- ExactTarget: ExactTarget/javascript
- Expensify Expensify/Style-Guide
- Flexberry: Flexberry/javascript-style-guide
- Gawker Media: gawkermedia/javascript
- General Electric: GeneralElectric/javascript
- GoodData: gooddata/gdc-js-style
- Grooveshark: grooveshark/javascript
- How About We: howaboutwe/javascript
- Huballin: huballin/javascript
- HubSpot: HubSpot/javascript
- Hyper: hyperoslo/javascript-playbook
- InfoJobs: InfoJobs/JavaScript-Style-Guide
- Intent Media: intentmedia/javascript
- Jam3: Jam3/Javascript-Code-Conventions
- JeopardyBot: kesne/jeopardy-bot
- JSSolutions: JSSolutions/javascript
- Kinetica Solutions: kinetica/javascript
- Mighty Spring: mightyspring/javascript
- MinnPost: MinnPost/javascript
- MitocGroup: MitocGroup/javascript
- ModCloth: modcloth/javascript
- Money Advice Service: moneyadviceservice/javascript
- Muber: muber/javascript
- National Geographic: natgeo/javascript
- National Park Service: nationalparkservice/javascript
- Nimbl3: nimbl3/javascript
- Orion Health: orionhealth/javascript
- OutBoxSoft: OutBoxSoft/javascript
- Peerby: Peerby/javascript
- Razorfish: razorfish/javascript-style-guide
- reddit: reddit/styleguide/javascript
- React: /facebook/react/blob/master/CONTRIBUTING.md#style-guide
- REI: reidev/js-style-guide
- Ripple: ripple/javascript-style-guide
- SeekingAlpha: seekingalpha/javascript-style-guide
- Shutterfly: shutterfly/javascript
- Springload: springload/javascript
- StudentSphere: studentsphere/javascript
- Target: target/javascript
- TheLadders: TheLadders/javascript
- T4R Technology: T4R-Technology/javascript
- VoxFeed: VoxFeed/javascript-style-guide
- Weggo: Weggo/javascript
- Zillow: zillow/javascript
- ZocDoc: ZocDoc/javascript
이 스타일 가이드는 다른 언어로도 이용할 수 있습니다.
Brazilian Portuguese: armoucar/javascript-style-guide
Bulgarian: borislavvv/javascript
Catalan: fpmweb/javascript-style-guide
Chinese (Simplified): sivan/javascript-style-guide
Chinese (Traditional): jigsawye/javascript
French: nmussy/javascript-style-guide
German: timofurrer/javascript-style-guide
Italian: sinkswim/javascript-style-guide
Japanese: mitsuruog/javacript-style-guide
Korean: tipjs/javascript-style-guide
Polish: mjurczyk/javascript
Russian: uprock/javascript
Spanish: paolocarrasco/javascript-style-guide
Thai: lvarayut/javascript-style-guide
- Find us on gitter.
(The MIT License)
Copyright (c) 2014 Airbnb
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
We encourage you to fork this guide and change the rules to fit your team's style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts.