본문 바로가기
C++ 200제/코딩 IT 정보

[ESLint es6] JavaScript 이해하기 2 최선의 예제

by vicddory 2019. 12. 20.

1편에서 이어지는 글입니다.



accessor-pairs

set 구문의 페어가 되는 get 구문의 정의를 강제합니다.


// NG

var object = {

  set foo (val) {

    this.val = val

  }

}


// OK

var object = {

  set foo (val) {

    this.val = val

  },

  get foo () {

    return this.val

  }

}


array-callback-return

Array 메소드의 콜백 함수에서 return 문장을 강제합니다.


// NG

let numList = [1, 2, 3].map((item) => {

  item * item

})


// OK

let numList = [1, 2, 3].map((item) => {

  return item * item

})

block-scoped-var

var 변수를 블록 외부에서 사용했을 때 경고합니다.

이건 호이스팅에 의한 버그를 피할 수 있습니다.


// NG

function something () {

  if (true) {

    var foo = 'hello'

  }

  console.log(foo)

}


// OK

function something () {

  var foo

  if (true) {

    foo = 'hello'

  }

  console.log(foo)

}


class-methods-use-this

class 메소드가 this 이용하는 것을 강요합니다.

this를 이용하지 않는 경우, 정적 함수(static)로 정의할 수 있습니다.


// NG

class Something {

  constructor () {

    this.num = 1

  }

  print () {

    console.log(1)

  }

}


// OK

class Something {

  constructor () {

    this.num = 1

  }

  static print () {

    console.log(1)

  }

}

class Something {

  constructor () {

    this.num = 1

  }

  print () {

    console.log(this.num)

  }

}


complexity

복잡도를 제한합니다.


// NG: eslint complexity: ["error", 2]

function something (i) {

  if (i === 1) {

    console.log('foo') // 1

  } else if (i === 2) {

    console.log('bar') // 2

  } else {

    console.log('baz') // 3

  }

}


consistent-return

return문이 항상 뭔가를 돌려주는지, 항상 아무것도 돌려주지 않는지 강제합니다.


// NG

function something1 (i) {

  if (i === 1) {

    return 'foo'

  } else {

    return

  }

}


// OK

function something2 (i) {

  if (i === i) {

    return 'foo'

  } else {

    return 'bar'

  }

}

function something3 (i) {

  if (i === i) {

    return

  }

}


curly

중괄호 사용을 요구합니다.

JavaScript에서는 블록 문이 하나만 존재하면 중괄호를 생략할 수 있지만, 이것은 버그의 원인이 되거나 코드를 읽을 때 헷갈릴 수 있으므로 중괄호를 생략하지 않는 것이 모범 사례로 간주하고 있습니다.


// NG

if (foo) return 'foo'


// OK

if (foo) {

  return 'foo'

}


default-case

switch문에서 defaultCase 적을 것을 요구합니다.

defaultCase를 항상 명시하는 것이 개발자의 의도를 명확하게 이해시키기 위해 좋은 일이라고 생각합니다.


// NG

switch (foo) {

  case 1:

    console.log('foo is 1')

    break

  case 2:

    console.log('foo is 2')

    break

}


// OK

switch (foo) {

  case 1:

    console.log('foo is 1')

    break

  case 2:

    console.log('foo is 2')

    break

  default:

    break

}


switch (foo) {

  case 1:

    console.log('foo is 1')

    break

  case 2:

    console.log('foo is 2')

    break

  // no default

}


dot-location

dot 도트 점(.)의 앞뒤에 줄 바꿈 넣는 것을 요구합니다.

점 위치에 일관성이 있으므로 가독성이 향상됩니다.


/* eslint dot-location: ["error", "object"] */

// NG

let property = object

  .property


// OK

let property = object.

  property

let property = object.property


/* eslint dot-location: ["error", "property"] */

// NG

let property = object.

  property


// OK

let property = object

  .property

let property = object.property


dot-notation

개체 속성에 엑세스할 때 점 표기법을 요구합니다.

JavaScript에서는 브래킷 표기법에서 객체 속성으로 엑세스할 수 있지만, 도트 표기법이 가독성과 압축 효율이 우수합니다.


// NG

let foo = object['property']


// OK

let foo = object.property


let propertyName = 'property'

let foo = object[propertyName]


eqeqeq

==와 != 대신 ===와 !==를 요구합니다.

==와 !=은 애매한 문제를 찾기 어렵기 때문에 ===과 !== 쪽의 형식이 안전하고 좋은 습관입니다.


// NG

if (foo == 'foo') {


}


// OK

if (foo === 'foo') {


}


guard-for-in

for in 문장을 사용할 때 if 문장에서 조사하는 것을 강요합니다.

for in은 프로토타입 체인에서 상속된 속성도 루프에 포함하는 것을 의도한 것으로 오독할 수 있기 때문입니다.


// NG

for (const key in object) {

  console.log(key)

}


// OK

for (const key in object) {

  if (object.hasOwnProperty(key)) {

    console.log(key)

  }

}

no-alert

alert 함수 사용을 금지합니다.

alert과 confirm, prompt 함수로 표시되는 UI는 더 나은 사용자 정의 UI로 대체합니다. 또한, 디버깅에 이용하는 일도 있으므로 production에서 빌드할 때 삭제해야 합니다.


// NG

alert('foo')

confirm('bar')

prompt('baz')


no-caller

arguments.caller와 arguments.callee 사용하는 것을 금지합니다.

이러한 기능은 향후 JavaScript, ECMAScript5, strict mode에서 금지됩니다.


// NG

function foo () {

  console.log(arguments.caller)

  arguments.callee()

}


no-case-declarations

lexical declarations(let, const, function, class)를 case, default 절에서 사용하는 것을 금지합니다.

switch 문 전체에 정의된 것처럼 보이지만, 실제론 그 코드에 도달했을 때만 초기화되지 않습니다.


lexical declarations을 case에서 이용하는 경우 괄호로 묶어야 합니다.


// NG

switch (something) {

  case 1:

    let foo = 'foo'

    break

  case 2:

    const bar = 'bar'

    break

  case 3:

    function baz () {

      console.log('baz')

    }

    break

  default:

    class qux {

    }

}


// OK

switch (something) {

  case 1: {

    let foo = 'foo'

  }

  case 2: {

    const bar = 'bar'

  }

  case 3: {

    function baz () {

      console.log('baz')

    }

  }

  default: {

    class qux {


    }

  }

}


no-div-regex

정규표현식 시작 부분에서 나누기 연산자를 허용하지 않습니다.


// NG

let foo = /=foo/


// OK

let foo = /\=foo/


no-else-return

else 전에 return하는 것을 금지합니다.


// NG

function something () {

  if (foo) {

    return 'foo'

  } else {

    return 'bar' 

  }

}


// OK

function something () {

  if (foo) {

    return 'foo'

  }

  return 'bar'

}


no-empty-function

빈 함수를 금지합니다. 의도적으로 정의할 경우 주석을 추가합니다.


// NG

function empty () {


}


// OK

function empty () {

  // do nothing.

}


no-empty-pattern

빈 디스트럭처 패턴을 금지합니다.

많은 경우 기본값을 지정하는 것은 실수입니다.


// NG

let {property: {}} = object


// OK

let {property = {}} = object


no-eq-null

null 비교 시에는 엄격한 비교를 요구합니다.

의도하지 않은 비교에 의한 잠재적인 버그를 방지합니다.


// NG

if (foo == null) {


}

if (foo != null)


// OK

if (foo === null) {


}

if (foo !== null) {


}


no-eval

eval 함수 사용을 금지합니다.

eval 함수는 위험하고 악용될 가능성이 높습니다.


// NG

var foo  = eval('{a: 1, b: 2}')


no-extend-native

내장 객체 확장을 금지합니다.


// NG

Object.prototype.foo = 'foo'


no-extra-bind

불필요한 bind 기능을 금지합니다.


// NG

let foo = function () {

  console.log('bar')

}.bind(this)


let foo = function () {

  (function () {

    console.log(this.bar)

  })

}.bind({bar: 'bar'})


// OK

let foo = function () {

  console.log(this.bar)

}.bind({bar: 'bar'})


no-extra-label

불필요한 라벨을 금지합니다.


// NG

LOOP1: while(true) {

  break LOOP1

}


// OK

LOOP1: while(true) {

  while (true) {

    break LOOP1

  }

}


no-fallthrough

case 문장에서 폴스루를 금지합니다.

의도적으로 개행할 경우 주석으로 설명합니다.


// NG

switch (foo) {

  case 1:

    doSomething1()

  case 2:

    doSomething2()

}


// OK

switch (foo) {

  case 1:

    doSomething1()

    break

  case 2:

    doSomething2()

    break

}


switch (foo) {

  case 1:

    doSomething1()

    // fall through

  case 2:

    doSomething2()

}

no-floating-decimal

소수점 앞의 숫자 생략을 금지합니다.

숫자와 dot 도트 점을 쉽게 구별하기 위함입니다.


// NG

let decimal = .1


// OK

let decimal = 0.1


no-global-assign

읽기 전용 전역 변수에 대입을 금지합니다.


// NG

window = false

Object = {}

undefined = 'undefined'


no-implicit-coercion

짧은 코드 기법에 의한 암시적 변환을 금지합니다. 형식 변환하는 경우 명시적인 방법을 사용합니다.


// NG

let isFoo = !!foo


if (~foo.indexOf(0)) {


}


// OK

let isFoo = Boolean(foo)


if (foo.indexOf(0) !== -1) {


}


no-implicit-globals

전역 글로벌 변수와 함수 선언하는 것을 금지합니다.

의도적으로 전역으로 선언한 경우 window 및 버튼 self를 명시합니다.


// NG

function foo () {}

var foo = 'foo'


// OK

window.foo = function () {}

self.foo = 'foo'


no-implied-eval

암묵적인 eval()을 금지합니다.

setTimeout(), setInterval(), execScript()의 첫 번째 인수에 문자열을 지정한 경우 암시적으로 eval()이 실행되어 버립니다. (Internet Explorer only)


// NG

setTimeout(`function () {

  console.log("foo") 

}`, 1000)


no-invalid-this

this 키워드를 클래스와 클래스 객체 외부에서 사용하는 것을 금지합니다.

strict mode 경우 this는 undefined 되고 TypeError 발생시킬 가능성이 있습니다.


// NG

this.foo = 'foo'


function func () {

  this.foo = 'foo'

}


let foo = () => {

  this.foo = 'foo'

}


// OK

function Func () {

  this.foo = 'foo'

}


class Foo {

  constructor () {

    this.foo = 'foo'

  }

}


no-iterator

비추천 ... __iterator__ 프로퍼티를 금지합니다.

ES6의 Iterator와 Generator를 대신 사용합니다.


// NG

Foo.prototype.__iterator__ = function () {}


no-labels

label 문장을 금지합니다.

label은 그다지 사용하지 않는 경향이 있지만, 제어 흐름을 이해하기 어렵고 오류가 발생하기 쉽습니다.


// NG

label:

  while(foo) {

    while (bar) {

      break label

    }

  }


// OK

while(foo) {

  while (bar) {

    break

  }

  break

}


no-lone-blocks

불필요한 중첩 블록을 금지합니다.


// NG

{

  var foo = 'foo'

}


// OK

{

  let foo = 'foo'

}


no-loop-func

루프에서 함수 선언 시, 함수 표현식 사용을 금지합니다.

상황에 따라 예기치 않은 동작할 가능성이 있습니다.


// NG

var funcs = []

for (var i = 0; i < 10; i++) {

  funcs[i] = function () {

    return i

  }

}


for (var i = 0; i < 10; i++) {

  function foo () {

    console.log(i)

  }

  foo()

}


// OK

var funcs = []

for (let i = 0; i < 10; i++) {

  funcs[i] = function () {

    return i

  }

}

for (let i = 0; i < 10; i++) {

  function foo () {

    console.log(i)

  }

  foo()

}


no-magic-numbers

매직 넘버를 금지합니다.

매직 넘버를 명명된 상수로 선언하는 것이 읽고 이해하기 쉬우며 리팩토링도 쉬워집니다.


// NG

let array = ['foo', 'bar', 'baz']

console.log(array[2])


// OK

let array = ['foo', 'bar', 'baz']

let index = 2

console.log(array[index])


no-multi-spaces

조건식, 선언, 배열, 오브젝트, 시퀀스, 함수 매개 변수의 주위에 공백 여러 개 추가를 금지합니다.


// NG

if (foo  === 'foo') {


}

function foo  () {


}

const foo = [1,  2, 3]


no-multi-str

여러 줄의 문자열을 금지합니다.

\ 줄 바꿈 앞에 지정함으로써 여러 줄의 문자열을 만들 수 있습니다만, 원래 JavaScript에서 공식적으로 규정된 것이 없으므로 나쁜 습관이라 생각하는 사람들이 있습니다.


// NG

let foo = 'foo \

  bar \

  baz'


// OK

let foo = 'foo \n' +

  'bar \n' +

  'baz'

no-new

변수에 할당하지 않은 인스턴스 생성(new)을 금지합니다.

변수에 할당하지 않으면 많은 생성자가 필요하지 않으며 함수로 대체할 수 있습니다.


// NG

new Foo()


// OK

let foo = new Foo()

foo()


no-new-func

Function 생성자 사용을 금지합니다.

Function은 가독성이 낮고, 디버깅이 어렵기 때문에 나쁜 습관입니다.


// NG

let func = new Function('a', 'b', 'return a + b')


no-new-wrappers

new String, new Number, new Boolean 사용을 금지합니다.

프리미티브 값을 생성하지 않고 실제로는 Object가 생성되므로 개발자 혼란을 초래할 수 있습니다.


// NG

let str = new String('str')

let num = new Number(1)

let bool = new Boolean(false)


no-octal

8진수 표기를 금지합니다. 8진수 표기는 EcmaScript5에서 폐지되어 strict 모드에서 오류가 발생합니다.


// NG

let foo = 071


no-octal-escape

8진수 이스케이프 시퀀스 사용을 금지합니다.


// NG

let foo = "Copyright \251";


// OK

let foo = "Copyright \u00A9"; 


no-param-reassign

함수 매개 변수(인수)에 다시 대입하는 것을 금지합니다.

개발자가 의도하지 않은 오류가 발생하는 것을 방지합니다.


// NG

function doSomething(arg) {

  arg = 'foo'

}


// OK

function doSomething(arg) {

  let foo = arg

  foo = 'foo'

}


no-proto

__proto__ 사용을 금지합니다.

__proto__는 EcmaScript 3.1 이상에서 폐지되었으므로 대신 getPrototypeOf를 사용하세요.


// NG

let proto = obj.__proto__


// OK

let proto = Object.getPrototypeOf(obj)


no-redeclare

같은 범위 내에서 같은 이름의 변수 선언을 금지합니다.


// NG

var foo = 'foo1'

var foo = 'foo2'


// OK

var bar = 'bar1'

bar = 'bar2'


no-restricted-properties

지정된 객체 속성의 사용을 금지할 수 있습니다.


/*

"no-restricted-properties": [2, {

  "object": "obj",

  "property": "prop"

}]

*/


// NG

let obj = {}

console.log(obj.prop)


no-return-assign

return 문장에 대입하는 것을 금지합니다.

개발자 혼란을 초래하고 오류를 발생시킬 여지가 있습니다.


// NG

function doSomething() {

  return a = 1 + 2

}


no-return-await

return await 문장을 금지합니다.

async function을 이해하지 않고 실제로는 쓸모없이 처리되기 때문입니다.


// NG

async function doSomething() {

  return await foo()

}


// OK

async function doSomething() {

  await foo()

  return

}


no-script-url

JavaScript 프로토콜 javascript: 사용을 금지합니다.


// NG

location.href = 'javascript:void(0)'


no-self-assign

자신에게 할당을 금지합니다.


// NG

window = window


no-self-compare

자신과의 비교를 금지합니다.


// NG

if (foo === foo) {


}


no-sequences

다음 예외를 제외하고 쉼표 연산자 사용을 금지합니다.


for 문의 초기화 또는 업데이트 부분

식의 순서가 명시적이고 괄호 안에 있는 경우


// NG

foo = doSomething(), val


// OK

foo = (doSomething(), val)


no-throw-literal

예외 발생 시 Error 객체를 throw를 강제합니다.

예외 처리에 일관성을 갖기 위해서입니다.


// NG

throw 1

throw { error: true }


// OK

throw new Error()

throw new Error('error')


no-unmodified-loop-condition

루프 조건이 변경되지 않는 것을 금지합니다.

개발자 실수를 미연에 방지합니다.


// NG

while (node) {

  doSomething(node);

}


// OK

while (node) {

  doSomething(node);

  node = node.parent;

}

no-unused-expressions

사용되지 않는 표현을 금지합니다.


// NG

function doSomething() {

  foo + 1

}


// OK

function doSomething() {

  return foo + 1

}


no-unused-labels

사용하지 않는 라벨을 금지합니다.


// NG

A: var foo = 0;


// OK

A: {

  if (foo()) {

      break A;

  }

  bar();

}


no-useless-call

불필요한 .call()과 .apply() 사용을 금지합니다.

함수 호출에 사용할 수 있지만, 일반 함수 호출보다 느립니다.


// NG

foo.call(undefined, 1, 2, 3);

foo.call(null, 1, 2, 3);

obj.foo.call(obj, 1, 2, 3);


// OK

foo.call(obj, 1, 2, 3);

obj.foo.call(null, 1, 2, 3);

obj.foo.call(otherObj, 1, 2, 3);


no-useless-concat

불필요한 문자 연결을 금지합니다.


// NG

var a = `some` + `string`;

var a = '1' + '0';


// OK

var c = a + b;

var c = '1' + a;

var a = 1 + '1';


no-useless-escape

불필요한 이스케이프를 금지합니다.


// NG

"\'";

`\"${foo}\"`;

`\#{foo}`;


// OK

"\"";

`\${${foo}}`;

`$\{${foo}}`;


no-useless-return

불필요한 return 문장을 금지합니다.


// NG

function foo() {

  doSomething();

  return;

}


// OK

function foo() {

  return doSomething();

}


no-void

void 연산자를 금지합니다.

어떤 코딩 스타일에서는 void 연산자는 읽기 어렵습니다.


// NG

void foo

var foo = void bar();


no-warning-comments

경고 코멘트를 금지합니다.

경고 코멘트는 배포 환경 구성하기 전에 제거해야 합니다.


// NG

function callback(err, results) {

  if (err) {

    console.error(err);

    return;

  }

  // TODO

}


// OK

function callback(err, results) {

  if (err) {

    console.error(err);

    return;

  }

  // NOT READY FOR PRIME TIME

  // but too bad, it is not a predefined warning term

}


no-with

with 문장 사용을 금지합니다.

with 문장은 비추천이며, EcmaScript5의 strict 모드는 금지되어 있습니다.


// NG

with (point) {

  r = Math.sqrt(x * x + y * y);

}


// OK

const r = ({x, y}) => Math.sqrt(x * x + y * y);


prefer-promise-reject-errors

Promise에서 reject 하려면 Error 오브젝트 설정을 요구합니다.


// NG

Promise.reject("something bad happened");

Promise.reject();


// OK

Promise.reject(new Error("something bad happened"));

Promise.reject(new TypeError("something bad happened"));


radix

parseInt 함수 사용 시 radix 지정을 요구합니다.

EcmaScript5 이전까지 0으로 시작하는 숫자의 문자열을 8진수로 해석해 버리는 일이 있었습니다.


// NG

var num = parseInt("071");

var num = parseInt(someValue);


// OK

var num = parseInt("071", 10);

var num = parseInt("071", 8);


require-await

await 없는 async 함수를 금지합니다.

리팩토링 등 의도하지 않은 결과를 방지합니다.


// NG

async function foo() {

  doSomething();

}


bar(async () => {

  doSomething();

});


// OK

async function foo() {

  await doSomething();

}


bar(async () => {

  await doSomething();

});


vars-on-top

변수 선언을 맨 앞에서 할 것을 강요합니다.


// NG

function doSomething() {

  var a = 1

  console.log(a)

  var b = 2

}


for (var i = 0; i < 10; i++) {

  console.log(i)

}


// OK

function doSomething() {

  var a = 1

  var b = 2

  console.log(a)

}


for (let i = 0; i < 10; i++) {

  console.log(i)

}

wrap-iife

즉시 함수(IIFE)를 괄호로 둘러서 쌓아야 합니다.

함수 표현식이 괄호 없이 실행되는 데 비해 함수 선언은 괄호가 없는 경우 동작하지 않습니다.


// NG

var x = function () { return { y: 1 } }()


// OK

var x = (function () { return { y: 1 } }())


yoda

요다 기법을 강제하거나 금지합니다.

변수와 리터럴 값을 비교할 때 피연산자의 위치에 일관성을 갖게 하기 위해서입니다.


/* "yoda": "error" */

// NG

if ('red' === color) {


}


// OK

if (color === 'red') {


}


/* "yoda": ["error", "always"] */

// NG

if (color === 'red') {


}


// OK

if ('red' === color) {


}



다 읽으셨으면 이전 글도 함께 읽어보세요.




댓글