oris9
[Javascript] 코딩컨벤션 지키면서 코드 짜기 (에어비앤비 코딩 컨벤션) 본문
컨벤션을 지키면서 코드를 짜자!!!!!!!!!!!!!!!
코드리뷰에서 C언어의 나쁜 습관이 보인다고 하셨다
아무래도 코딩테스트 공부하면서 다른 분들의 풀이를 참고하다보니 그런 습관이 베인 것 같다 왜냐면 난 씨언어 모르니깐!!
모르는.거. 한가득 🥵🥵🥵🥵🥵🤢 지킬거. 한가득 ㅎㅎ 🤩 빠이팅 !
읽는 사람이 읽기 편하게 유지보수하기 편하게 작성하자 아자자
(원어)https://github.com/airbnb/javascript?tab=readme-ov-file
(한국어)https://github.com/ParkSB/javascript-style-guide
4.6Array.from 반복 가능한 매핑에 스프레드 대신 사용하세요 .... 중간 배열 생성을 방지하기 때문입니다.
// bad
const baz = [...foo].map(bar);
// good
const baz = Array.from(foo, bar);
4.7
// 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;
});
4.8 배열에 여러 줄이 있는 경우 배열 괄호를 연 후, 배열 괄호를 닫기 전에 줄 바꿈을 사용하세요.
// 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,
];
5.1 객체의 여러 속성에 접근하고 사용할 때 객체 구조 분해를 사용하세요. 에스린트:prefer-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.3 여러 반환 값에는 배열 구조 분해가 아닌 객체 구조 분해를 사용하세요.
왜? 시간이 지남에 따라 새 속성을 추가하거나 호출 사이트를 중단하지 않고 사물의 순서를 변경할 수 있습니다.
// bad
function processInput(input) {
// then a miracle occurs
return [left, right, top, bottom];
}
// the caller needs to think about the order of return data
const [left, __, top] = processInput(input);
// good
function processInput(input) {
// then a miracle occurs
return { left, right, top, bottom };
}
// the caller selects only the data they need
const { left, top } = processInput(input);
6.1'' 문자열에는 작은따옴표를 사용하세요 . 에스린트:quotes
// bad
const name = "Capt. Janeway";
// bad - template literals should contain interpolation or newlines
const name = `Capt. Janeway`;
// good
const name = 'Capt. Janeway';
6.2 한 줄이 100자를 초과하게 만드는 문자열은 문자열 연결을 사용하여 여러 줄에 걸쳐 작성해서는 안 됩니다.
왜? 끊어진 문자열은 작업하기 힘들고 코드 검색도 어렵게 만듭니다.
// 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.4eval() 문자열에는 절대 사용하지 마세요 . 너무 많은 취약점을 열어줍니다. 에스린트:no-eval
6.5 문자열에서 문자를 불필요하게 이스케이프 처리하지 마세요. 에스린트:no-useless-escape
왜? 백슬래시는 가독성을 저하시키므로 필요한 경우에만 사용되어야 합니다.
// bad
const foo = '\'this\' \i\s \"quoted\"';
// good
const foo = '\'this\' is "quoted"';
const foo = `my name is '${name}'`;
7.1 함수 선언 대신 명명된 함수 표현식을 사용하세요. 에스린트: func-style,func-names
왜? 함수 선언은 호이스팅됩니다. 즉, 파일에 정의되기 전에 함수를 참조하는 것이 너무 쉽다는 뜻입니다. 이는 가독성과 유지 관리성에 해를 끼칩니다. 함수의 정의가 파일의 나머지 부분을 이해하는 데 방해가 될 만큼 크거나 복잡하다면, 이제 해당 정의를 자체 모듈로 추출해야 할 때입니다! 이름이 포함된 변수에서 유추되는지 여부에 관계없이 표현식의 이름을 명시적으로 지정하는 것을 잊지 마십시오(이는 최신 브라우저나 Babel과 같은 컴파일러를 사용할 때 종종 발생합니다). 이는 오류의 호출 스택에 대한 모든 가정을 제거합니다. ( 논의 )
// bad
function foo() {
// ...
}
// bad
const foo = function () {
// ...
};
// good
// lexical name distinguished from the variable-referenced invocation(s)
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};
7.2 즉시 호출되는 함수 표현식을 괄호로 묶습니다. 에스린트:wrap-iife
왜? 즉시 호출되는 함수 표현식은 단일 단위입니다. 이를 모두 감싸고 해당 호출 parens를 parens로 묶어 이를 명확하게 표현합니다. 어디에나 모듈이 있는 세상에서는 IIFE가 거의 필요하지 않습니다.
// immediately-invoked function expression (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());
7.3 비함수 블록( if, while등)에서는 함수를 선언하지 마십시오. 대신 함수를 변수에 할당하십시오. 브라우저에서는 이를 허용하지만 모두 다르게 해석하므로 나쁜 소식입니다. 에스린트:no-loop-func
7.4 참고: ECMA-262는 a를 block문의 목록으로 정의합니다. 함수 선언은 명령문이 아닙니다.
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
let test;
if (currentUser) {
test = () => {
console.log('Yup.');
};
}
7.5 매개변수 이름을 지정하지 마십시오 arguments. 이는 arguments모든 함수 범위에 제공되는 객체 보다 우선합니다 .
// bad
function foo(name, options, arguments) {
// ...
}
// good
function foo(name, options, args) {
// ...
}
7.6 절대 사용하지 마세요 arguments. 대신에 나머지 구문을 사용하세요 .... 에스린트:prefer-rest-params
왜? ...어떤 인수를 가져오려는지에 대해 명시적입니다. 게다가 나머지 인수는 실제 배열이며 단순히 배열과 유사한 arguments.
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
7.7 함수 인수를 변경하는 대신 기본 매개변수 구문을 사용하세요.
// really bad
function handleThings(opts) {
// No! We shouldn’t mutate function arguments.
// Double bad: if opts is falsy it'll be set to an object which may
// be what you want but it can introduce subtle bugs.
opts = opts || {};
// ...
}
// still bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
7.8 기본 매개변수로 부작용을 피하세요.
왜? 그들은 추론하기가 혼란스럽습니다.
let b = 1;
// bad
function count(a = b++) {
console.log(a);
}
count(); // 1
count(); // 2
count(3); // 3
count(); // 3
7.9 항상 기본 매개변수를 마지막에 두십시오. 에스린트:default-param-last
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
7.10 새로운 함수를 생성하기 위해 Function 생성자를 사용하지 마세요. 에스린트:no-new-func
왜? 이런 방식으로 함수를 생성하면 eval()취약점이 열리는 와 유사하게 문자열을 평가합니다 .
// bad
const add = new Function('a', 'b', 'return a + b');
// still bad
const subtract = Function('a', 'b', 'return a - b');
7.12 매개변수를 변경하지 마세요. 에스린트: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 절대 매개변수를 재할당하지 마세요. 에스린트:no-param-reassign
왜? 매개변수를 재할당하면 특히 개체에 액세스할 때 예기치 않은 동작이 발생할 수 있습니다 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) {
// ...
}
7.14... 가변 함수를 호출하려면 스프레드 구문을 사용하는 것이 좋습니다 . 에스린트:prefer-spread
왜? 더 깨끗하고 컨텍스트를 제공할 필요 가 없으며 new.apply
// bad
const x = [1, 2, 3, 4, 5];
console.log.apply(console, x);
// good
const x = [1, 2, 3, 4, 5];
console.log(...x);
// bad
new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
// good
new Date(...[2016, 8, 5]);
8.1 인라인 콜백을 전달할 때와 같이 익명 함수를 사용해야 하는 경우 화살표 함수 표기법을 사용하세요. 에스린트: prefer-arrow-callback,arrow-spacing
왜? this이는 일반적으로 원하는 것이며 보다 간결한 구문인 의 컨텍스트에서 실행되는 함수 버전을 생성합니다 .
왜 안 돼? 상당히 복잡한 함수가 있는 경우 해당 논리를 자체 명명된 함수 표현식으로 이동할 수 있습니다.
// 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명령문을 사용하십시오. 에스린트: arrow-parens,arrow-body-style
왜? 구문 설탕. 여러 기능이 함께 연결되어 있으면 잘 읽혀집니다.
8.3 표현식이 여러 줄에 걸쳐 있는 경우 가독성을 높이기 위해 괄호로 묶습니다.
왜? 함수가 시작하고 끝나는 위치를 명확하게 보여줍니다.
// bad
['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call(
httpMagicObjectWithAVeryLongName,
httpMethod,
)
);
// good
['get', 'post', 'put'].map((httpMethod) => (
Object.prototype.hasOwnProperty.call(
httpMagicObjectWithAVeryLongName,
httpMethod,
)
));
8.4 명확성과 일관성을 위해 주장 주위에는 항상 괄호를 포함하십시오. 에스린트:arrow-parens
왜? 인수를 추가하거나 제거할 때 차이 변동을 최소화합니다
// bad
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].map((x) => x * x);
// bad
[1, 2, 3].map(number => (
`A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));
// good
[1, 2, 3].map((number) => (
`A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));
// 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;
});
8.6 암시적 반환을 사용하여 화살표 함수 본문의 위치를 강제합니다. 에스린트:implicit-arrow-linebreak
// bad
(foo) =>
bar;
(foo) =>
(bar);
// good
(foo) => bar;
(foo) => (bar);
(foo) => (
bar
)
9.1 항상 를 사용하세요 class. 직접 조작하는 것을 피하세요 prototype
9.2 상속에 사용합니다 extends.
// 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.3this 메소드는 메소드 체이닝에 도움을 주기 위해 돌아올 수 있습니다 .
// 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()}`;
}
}
9.5 클래스는 지정되지 않은 경우 기본 생성자를 갖습니다. 빈 생성자 함수나 부모 클래스에 위임하는 함수는 필요하지 않습니다. 에스린트:no-useless-constructor
// 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';
}
}
9.7this 외부 라이브러리나 프레임워크에서 특정 비정적 메서드 사용을 요구하지 않는 한 클래스 메서드는 정적 메서드를 사용하거나 정적 메서드로 만들어야 합니다 . 인스턴스 메서드라는 것은 수신자의 속성에 따라 다르게 동작한다는 것을 나타내야 합니다. 에스린트:class-methods-use-this
// bad
class Foo {
bar() {
console.log('bar');
}
}
// good - this is used
class Foo {
bar() {
console.log(this.bar);
}
}
// good - constructor is exempt
class Foo {
constructor() {
// ...
}
}
// good - static methods aren't expected to use this
class Foo {
static bar() {
console.log('bar');
}
}
10.1 항상 비표준 모듈 시스템보다는 모듈( 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;
10.5 변경 가능한 바인딩을 내보내지 마세요. 에스린트:import/no-mutable-exports
왜? 일반적으로 변형은 피해야 하지만, 특히 변경 가능한 바인딩을 내보낼 때 더욱 그렇습니다. 일부 특수한 경우에는 이 기술이 필요할 수 있지만 일반적으로 상수 참조만 내보내야 합니다.
// bad
let foo = 3;
export { foo };
// good
const foo = 3;
export { foo };
10.9 모듈 import 문에서 Webpack 로더 구문을 허용하지 않습니다. 에스린트:import/no-webpack-loader-syntax
왜? 가져오기에서 Webpack 구문을 사용하므로 코드가 모듈 번들러에 연결됩니다. NET에서 로더 구문을 사용하는 것이 좋습니다 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';
10.10 JavaScript 파일 이름 확장자 eslint를 포함하지 마세요:import/extensions
왜? 확장을 포함하면 리팩토링이 금지되고 모든 소비자에게 가져오는 모듈의 구현 세부 정보가 부적절하게 하드코딩됩니다.
// 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';
11.1 반복자를 사용하지 마세요. for-in또는 같은 루프 대신 JavaScript의 고차 함수를 선호합니다 for-of. 에스린트:no-iterator no-restricted-syntax
왜? 이는 불변의 규칙을 시행합니다. 값을 반환하는 순수 함수를 다루는 것은 부작용보다 추론하기가 더 쉽습니다.
map()/ every()/ filter()/ find()/ findIndex()/ reduce()/ / ...를 사용 some()하여 배열을 반복하고, Object.keys()/ Object.values()/를 Object.entries()사용하여 객체를 반복할 수 있는 배열을 생성합니다.
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);
12.1 속성에 접근할 때 점 표기법을 사용하세요. 에스린트:dot-notation
12.2[] 변수로 속성에 접근할 때 대괄호 표기법을 사용하세요 .
12.3** 지수를 계산할 때 지수 연산자를 사용하세요 . 에스린트: prefer-exponentiation-operator.
// bad
const binary = Math.pow(2, 10);
// good
const binary = 2 ** 10;
13.3 모든 const항목을 그룹화한 다음 모든 let항목을 그룹화합니다.
왜? 이는 나중에 이전에 할당된 변수 중 하나에 따라 변수를 할당해야 할 때 유용합니다.
// 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
// 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;
}
13.5 변수 할당을 연결하지 마세요. 에스린트:no-multi-assign
왜? 변수 할당을 연결하면 암시적 전역 변수가 생성됩니다.
// bad
(function example() {
// JavaScript interprets this as
// let a = ( b = ( c = 1 ) );
// The let keyword only applies to variable a; variables b and c become
// global variables.
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
// the same applies for `const`
13.6 단항 증가 및 감소( ++, --) 사용을 피하세요. 에스린트no-plusplus
왜? eslint 문서에 따르면 단항 증가 및 감소 문은 자동 세미콜론 삽입의 대상이 되며 애플리케이션 내에서 값을 증가시키거나 감소시키면서 자동 오류가 발생할 수 있습니다. 또한 num += 1대신에 num++또는 같은 문을 사용하여 값을 변경하는 것이 더 표현력이 좋습니다 num ++. 단항 증가 및 감소 문을 허용하지 않으면 의도치 않게 값을 사전 증가/사전 감소시켜 프로그램에서 예기치 않은 동작을 유발할 수도 있습니다.
// bad
const array = [1, 2, 3];
let num = 1;
num++;
--num;
let sum = 0;
let truthyCount = 0;
for (let i = 0; i < array.length; i++) {
let value = array[i];
sum += value;
if (value) {
truthyCount++;
}
}
// good
const array = [1, 2, 3];
let num = 1;
num += 1;
num -= 1;
const sum = array.reduce((a, b) => a + b, 0);
const truthyCount = array.filter(Boolean).length;
13.7= 할당 전후에 줄바꿈을 피하세요 . 할당이 위반하는 경우 max-len값을 괄호로 묶습니다. 에스린트 operator-linebreak.
왜? 주변의 줄 바꿈은 =할당 값을 난독화할 수 있습니다.
// bad
const foo =
superLongLongLongLongLongLongLongLongFunctionName();
// bad
const foo
= 'superLongLongLongLongLongLongLongLongString';
// good
const foo = (
superLongLongLongLongLongLongLongLongFunctionName()
);
// good
const foo = 'superLongLongLongLongLongLongLongLongString';
14부터 한번 . 더읽기
'JavaScript' 카테고리의 다른 글
[Javascript] for, for-of, for-in, forEach 차이점 알아보기 (0) | 2024.06.03 |
---|---|
[Javascript] 자바스크립트 이벤트(버블링? 캡쳐링? 위임?) (0) | 2024.04.06 |
[Javascript] 두가지 복사.. 얕은 복사와 깊은 복사 (0) | 2024.03.30 |
[Javascript] var, let, const 열심히 비교해보기 (0) | 2024.03.30 |
[Javascript] ECMA스크립트(ECMAScript, 또는 ES) (0) | 2024.03.25 |