JavaScript에 대한 가장 합리적인 접근 방식
참고 : 이 가이드에서는 귀하가 Babel을 사용하고 있다고 가정하고 babel-preset-airbnb 또는 이와 동등한 것을 사용해야 합니다. 또한 airbnb-browser-shims 또는 이에 상응하는 기능을 사용하여 앱에 shim/polyfill을 설치한다고 가정합니다.
이 가이드는 다른 언어로도 제공됩니다. 번역 보기
기타 스타일 가이드
1.1 프리미티브 : 프리미티브 유형에 액세스하면 해당 값에 대해 직접 작업합니다.
string
number
boolean
null
undefined
symbol
bigint
const foo = 1 ;
let bar = foo ;
bar = 9 ;
console . log ( foo , bar ) ; // => 1, 9
1.2 복합 : 복합 유형에 액세스할 때 해당 값에 대한 참조 작업을 수행합니다.
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: prefer-const
, no-const-assign
왜? 이렇게 하면 참조를 다시 할당할 수 없어 버그가 발생하고 코드를 이해하기 어려워질 수 있습니다.
// bad
var a = 1 ;
var b = 2 ;
// good
const a = 1 ;
const b = 2 ;
2.2 참조를 다시 할당해야 하는 경우 var
대신 let
사용하세요. eslint: no-var
왜?
let
var
처럼 함수 범위가 아닌 블록 범위입니다.
// bad
var count = 1 ;
if ( true ) {
count += 1 ;
}
// good, use the let.
let count = 1 ;
if ( true ) {
count += 1 ;
}
2.3 let
과 const
모두 블록 범위이고 var
함수 범위입니다.
// const and let only exist in the blocks they are defined in.
{
let a = 1 ;
const b = 1 ;
var c = 1 ;
}
console . log ( a ) ; // ReferenceError
console . log ( b ) ; // ReferenceError
console . log ( c ) ; // Prints 1
위 코드에서 a
와 b
참조하면 ReferenceError가 발생하고 c
에는 숫자가 포함되어 있음을 알 수 있습니다. 이는 a
와 b
가 블록 범위이고 c
포함 함수로 범위가 지정되기 때문입니다.
⬆ 맨 위로 돌아가기
3.1 객체 생성에는 리터럴 구문을 사용하십시오. eslint: no-new-object
// bad
const item = new Object ( ) ;
// good
const item = { } ;
3.2 동적 속성 이름을 가진 객체를 생성할 때 계산된 속성 이름을 사용하세요.
왜? 이를 통해 객체의 모든 속성을 한 곳에서 정의할 수 있습니다.
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.3 객체 메소드 단축을 사용하세요. eslint: 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.4 속성값 약칭을 사용하세요. eslint: object-shorthand
왜? 더 짧고 설명적입니다.
const lukeSkywalker = 'Luke Skywalker' ;
// bad
const obj = {
lukeSkywalker : lukeSkywalker ,
} ;
// good
const obj = {
lukeSkywalker ,
} ;
3.5 객체 선언 시작 부분에 단축 속성을 그룹화하세요.
왜? 어떤 속성이 약어를 사용하고 있는지 쉽게 알 수 있습니다.
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.6 유효하지 않은 식별자인 인용 속성만 해당됩니다. eslint: quote-props
왜? 일반적으로 우리는 주관적으로 읽기가 더 쉽다고 생각합니다. 구문 강조가 향상되었으며 많은 JS 엔진에서 더욱 쉽게 최적화되었습니다.
// bad
const bad = {
'foo' : 3 ,
'bar' : 4 ,
'data-blah' : 5 ,
} ;
// good
const good = {
foo : 3 ,
bar : 4 ,
'data-blah' : 5 ,
} ;
3.7 hasOwnProperty
, propertyIsEnumerable
및 isPrototypeOf
와 같은 Object.prototype
메서드를 직접 호출하지 마세요. eslint: no-prototype-builtins
왜? 이러한 메서드는 문제의 개체에 대한 속성에 의해 숨겨질 수 있습니다
{ hasOwnProperty: false }
고려). 또는 개체가 null 개체(Object.create(null)
)일 수 있습니다. ES2022를 지원하는 최신 브라우저나 https://npmjs.com/object.hasown과 같은 폴리필을 사용하는 경우Object.hasOwn
Object.prototype.hasOwnProperty.call
대신 사용할 수도 있습니다.
// bad
console . log ( object . hasOwnProperty ( key ) ) ;
// good
console . log ( Object . prototype . hasOwnProperty . call ( object , key ) ) ;
// better
const has = Object . prototype . hasOwnProperty ; // cache the lookup once, in module scope.
console . log ( has . call ( object , key ) ) ;
// best
console . log ( Object . hasOwn ( object , key ) ) ; // only supported in browsers that support ES2022
/* or */
import has from 'has' ; // https://www.npmjs.com/package/has
console . log ( has ( object , key ) ) ;
/* or */
console . log ( Object . hasOwn ( object , key ) ) ; // https://www.npmjs.com/package/object.hasown
3.8 얕은 복사 객체에 대해서는 Object.assign
보다 객체 확산 구문을 선호합니다. 특정 속성이 생략된 새 객체를 얻으려면 객체 나머지 매개변수 구문을 사용하세요. eslint: prefer-object-spread
// very bad
const original = { a : 1 , b : 2 } ;
const copy = Object . assign ( original , { c : 3 } ) ; // this mutates `original` ಠ_ಠ
delete copy . a ; // so does this
// 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 }
⬆ 맨 위로 돌아가기
4.1 배열 생성에는 리터럴 구문을 사용하십시오. eslint: 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 += 1 ) {
itemsCopy [ i ] = items [ i ] ;
}
// good
const itemsCopy = [ ... items ] ;
4.4 반복 가능한 객체를 배열로 변환하려면 Array.from
대신 Spreads ...
사용하세요.
const foo = document . querySelectorAll ( '.foo' ) ;
// good
const nodes = Array . from ( foo ) ;
// best
const nodes = [ ... foo ] ;
4.5 배열과 유사한 객체를 배열로 변환하려면 Array.from
사용하세요.
const arrLike = { 0 : 'foo' , 1 : 'bar' , 2 : 'baz' , length : 3 } ;
// bad
const arr = Array . prototype . slice . call ( arrLike ) ;
// good
const arr = Array . from ( arrLike ) ;
4.6 Iterable에 대한 매핑에는 Spread ...
대신 Array.from
사용하세요. 중간 배열 생성을 방지하기 때문입니다.
// bad
const baz = [ ... foo ] . map ( bar ) ;
// good
const baz = Array . from ( foo , bar ) ;
4.7 배열 메서드 콜백에는 return 문을 사용하세요. 8.2에 따라 함수 본문이 부작용 없이 표현식을 반환하는 단일 문으로 구성된 경우 반환을 생략해도 괜찮습니다. eslint: array-callback-return
// 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 ) ;
} ) ;
// good
[ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] ] . reduce ( ( acc , item , index ) => {
const flatten = acc . concat ( item ) ;
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 ;
} ) ;
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 객체의 여러 속성에 접근하고 사용할 때 객체 구조 분해를 사용하세요. eslint: 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.2 배열 구조 분해를 사용하세요. eslint: prefer-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 ) {
// 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 문자열에는 작은따옴표 ''
사용하세요. eslint: 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.3 프로그래밍 방식으로 문자열을 구성할 때는 연결 대신 템플릿 문자열을 사용하세요. eslint: prefer-template
template-curly-spacing
왜? 템플릿 문자열은 적절한 개행 및 문자열 보간 기능을 통해 읽기 쉽고 간결한 구문을 제공합니다.
// bad
function sayHi ( name ) {
return 'How are you, ' + name + '?' ;
}
// bad
function sayHi ( name ) {
return [ 'How are you, ' , name , '?' ] . join ( ) ;
}
// bad
function sayHi ( name ) {
return `How are you, ${ name } ?` ;
}
// good
function sayHi ( name ) {
return `How are you, ${ name } ?` ;
}
eval()
사용하지 마세요. 너무 많은 취약점을 열어줍니다. eslint: no-eval
6.5 문자열에서 문자를 불필요하게 이스케이프 처리하지 마세요. eslint: no-useless-escape
왜? 백슬래시