/eslint-hijacking

Hijacking Style Guide

Primary LanguageJavaScript

Hijacking Style Guide

참고: 이 가이드는 Airbnb JavaScript style Guide에서 eslint에서 더 이상 사용하지 않는 규칙, node.js 버전이 업그레이드 됨에 따라 필요 없어진 규칙, 이견이 많은 규칙들을 제거하였습니다.

참조 (References)

  • 1.1 모든 참조에는 var 대신 const를 사용하세요.


    why? 참조를 재할당 할 수 없게 함으로써, 이해하기 어려운 동시에 버그로 이어지는 코드를 방지합니다.

    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;

  • 1.2 만약 참조를 재할당 해야 한다면 var 대신 let을 사용하세요.


    why? var처럼 함수스코프를 취하는 것 보다는 블록스코프를 취하는 let이 더 낫습니다.

    // bad
    var count = 1;
    if (true) {
      count += 1;
    }
    
    // good, use the let.
    let count = 1;
    if (true) {
      count += 1;
    }

  • 1.3 letconst 는 둘 다 블록스코프라는 것을 유의하세요.

    // const와 let은 선언된 블록 안에서만 존재합니다.
    {
      let a = 1;
      const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError

객체 (Object)

  • 2.1 객체를 생성할 때는 리터럴 문법을 사용하세요.


    // bad
    const item = new Object();
    
    // good
    const item = {};

  • 2.2 동적 속성을 갖는 객체를 생성할 때는 속성 계산명을 사용하세요.

    why? 이를 통해 객체의 모든 속성을 한 곳에서 정의할 수 있습니다.

    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,
    };

  • 2.3 메소드의 단축구문을 사용하세요.


    // bad
    const atom = {
      value: 1,
    
      addValue: function (value) {
        return atom.value + value;
      },
    };
    
    // good
    const atom = {
      value: 1,
    
      addValue(value) {
        return atom.value + value;
      },
    };

  • 2.4 속성의 단축구문을 사용하세요.


    why? 더 짧고 설명적입니다.

    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      lukeSkywalker: lukeSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
    };

  • 2.5 유효하지 않은 식별자에만 따옴표 속성을 사용하세요.


    why? 더 읽기 쉽습니다. 이렇게 하면 구문 하이라이팅이 잘 되고, 많은 자바스크립트 엔진이 더 쉽게 최적화 할 수 있습니다.

    // bad
    const bad = {
      'foo': 3,
      'bar': 4,
      'data-blah': 5,
    };
    
    // good
    const good = {
      foo: 3,
      bar: 4,
      'data-blah': 5,
    };

    but! 숫자 리터럴을 속성 키로 사용하는 경우에는 따온표를 사용하는게 좋습니다. 의도치 않은 결과가 발생할 수 있습니다. 아래와 같은 경우 속성 이름으로 사용되기 전에 문자열로 강제 변환되기 때문에 둘 다 속성이 "100"이됩니다.

    // bad 
    var object = {
        1e2: 1,
        100: 2
    };
    // 중복된 속성 이름을 가질 수 없기에 마지막으로 지정한 값으로 대체
    console.log(object) // {'100': 2 }
    
    // good 
    var object = {
        '1e2': 1,
        '100': 2
    };
    
    console.log(object) // { "100": 2, "1e2": 1 }

  • 2.6 객체에 대해 얕은 복사를 할 때는 Object.assign대신 객체 전개 구문을 사용하세요. 특정 속성이 생략된 새로운 개체를 가져올 때는 객체 나머지 연산자(object rest operator)를 사용하세요.


    // 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 }

배열 (Arrays)

  • 3.1 배열을 생성할 때 리터럴 구문을 사용하세요.


    why? Array 생성자를 사용하면 몇 가지 문제가 발생할 수 있습니다.
    첫째, Array 생성자를 사용할 때 한 가지 인수만을 전달할 수 있습니다. 이것은 오해의 소지가 있을 수 있고 버그를 일으킬 수 있습니다.
    둘째, Array라는 전역 객체가 다른 목적으로 재정의될 수 있으므로 코드가 예상대로 동작하지 않을 수 있습니다.

    // bad
    const items = new Array();
    
    // good
    const items = [];

  • 3.2 매핑할 때는 전개 구문 ... 대신 Array.from을 사용하세요. 중간 배열 생성을 방지와 성능 상의 문제가 있기 때문입니다.

    // bad
    const baz = [...foo].map(bar);
    
    // good
    const baz = Array.from(foo, bar);

  • 3.3 배열 메소드 콜백에는 리턴 구문을 사용하세요.


    why? 종종 리턴 구문을 넣어야하는 데 실수로 넣지 않을 때가 있습니다. 만약 반환을 사용하고 싶지 않거나 반환된 결과가 필요하지 않은 경우에는 forEach사용을 고려하세요.

    // 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;
    });

비구조화 (Destructuring)

  • 4.1 하나의 객체에서 여러 속성에 접근할 때는 객체 비구조화를 사용하세요.


    why? 비구조화는 속성들을 위한 임시 참조를 만들지 않도록 해주고, 객체의 반복적인 접근을 방지합니다. 반복적인 객체 접근은 중복 코드와 실수를 만들어내고, 더 많은 코드를 읽게 합니다. 또한 객체 비구조화는 블록에서 사용되는 객체의 구조를 저으이하는 단일한 위치를 제공함으로써 어떤 것이 사용되는지 알아내기 위해 모든 블록을 읽지 않아도 되도록 해줍니다.

    // 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}`;
    }

  • 4.2 배열 비구조화를 사용하세요.


    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;

문자열 (Strings)

  • 5.1 문자열을 생성하는 경우, 문자열 연결 대신 템플릿 문자열을 사용하세요.


    why? 템플릿 문자열은 덧붙이기와 줄바꿈을 제공하는 간결한 문법으로 가독성을 높여줍니다.

    // 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}?`;
    }

  • 5.2 절대로 문자열에 eval()을 사용하지 마세요. 너무나 많은 취약점을 만듭니다.

  • 5.3 문자열에 불필요한 이스케이프 문자를 사용하지 마세요.


    why? 백슬래시는 가독성을 해치기 때문에 필요할 때만 사용해야 합니다.

    // bad
    const foo = '\'this\' \i\s \"quoted\"';
    
    // good
    const foo = '\'this\' is "quoted"';
    const foo = `my name is '${name}'`;

Function

  • 6.1 즉시 호출 함수 표현식을 괄호로 감싸세요.


    why? 즉시 호출 함수 표현식은 하나의 단위이며, 괄호로 이것을 감싸면 괄호 안의 표현을 명확하게 해주기 때문입니다. 모듈을 어디에서나 사용한다면 즉시 호출 표현식은 전혀 필요하지 않다는 점을 주의하세요.

    // 즉시 호출 함수 표현식 (IIFE)
    (function () {
      console.log('Welcome to the Internet. Please follow me.');
    }());

  • 6.2 함수 이외의 불록(if, while, 등)에서 함수를 선언하지 마세요. 브라우저는 이를 허용하겠지만, 모두 다르게 해석합니다.

    • no-loop-func
    • 참고 : ECMA-262 명세는 블록을 구문의 일종으로 정의하고 있지만 함수선언은 구문이 아닙니다.

    // bad
    if (currentUser) {
      function test() {
        console.log('Nope.');
      }
    }
    
    // good
    let test;
    if (currentUser) {
      test = () => {
        console.log('Yup.');
      };
    }

  • 6.3 절대 매개변수 이름을 arguments라고 짓지 마세요. 이것은 함수 스코프에 전해지는 arguments 객체의 참조를 덮어써 버립니다.


    // bad
    function foo(name, options, arguments) {
      // ...
    }
    
    // good
    function foo(name, options, args) {
      // ...
    }

  • 6.4 절대 arguments를 사용하지마세요. 대신 나머지 문법(rest syntax) ...를 사용하세요.


    why? ...을 사용하면 몇 개의 매개변수를 이용하고 싶은지 확실히 할 수 있습니다. 더 나아가, 나머지 인자(rest arguments)는 arguments와 같은 Array-like 객체가 아닌 진짜 Array입니다.

    // bad
    function concatenateAll() {
      const args = Array.prototype.slice.call(arguments);
      return args.join('');
    }
    
    // good
    function concatenateAll(...args) {
      return args.join('');
    }

  • 6.5 기본 매개변수는 항상 뒤쪽에 두세요.


    // bad
    function handleThings(opts = {}, name) {
      // ...
    }
    
    // good
    function handleThings(name, opts = {}) {
      // ...
    }

  • 6.6 절대로 새로운 함수를 만들기 위해 함수 생성자를 사용하지 마세요.


    why? 이러한 방법으로 문자열을 평가해 함수를 만드는 것은 eval()과 같은 수준읜 취약점을 만듭니다.

    // bad
    var add = new Function('a', 'b', 'return a + b');
    
    // still bad
    var subtract = Function('a', 'b', 'return a - b');

  • 6.7 함수 시그니처에 공백을 넣으세요.


    why? 일관성을 갖는 것이 좋습니다. 그리고 이렇게 하면 이름을 추가하거나 지울 때 공백을 건드릴 필요가 없게 됩니다.

    // bad
    const f = function(){};
    const g = function (){};
    const h = function() {};
    
    // good
    const x = function () {};
    const y = function a() {};

  • 6.8 절대로 매개변수를 바꾸지 마세요.

    why? 매개변수로 전달된 객체를 조작하면 원래 호출처에서 원치 않는 사이드 이펙트를 일으킬 수 있습니다.

    // bad
    function f1(obj) {
      obj.key = obj.key || 1; // Mutate to normalize
      // Use obj.key
    }
    // good
    function f2(obj) {
      const key = obj.key || 1; // Normalize without mutating
      // Use key
    }

    해당 규칙에는 이견이 많습니다.
    관련 대안
    다음 이름으로 정의한 매개변수는 이 규칙을 무시합니다.

    • acc
    • accumulator
    • e
    • ctx
    • context
    • req
    • request
    • res
    • response
    • $scope
    • staticContext

  • 6.9 절대로 매개변수를 재할당하지 마세요.


    why? 매개변수를 재할당하는 것은 예측할 수 없는 결과를 불러 일으킵니다. 특히 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) {
      // ...
    }

  • 6.10 가변 인자 함수를 호출할 때는 전개 구문 ...을 사용하세요.


    why? 훨씬 더 깔끔합니다. 컨텍스트를 제공할 필요도 없고, applynew를 쉽게 구성할 수도 없습니다.

    // 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]);

  • 6.11 여러 줄의 시그니처 또는 호출을 취하는 함수는 이 가이드에 있는 다른 것들처럼 들여쓰기가 되어야 합니다. 한줄에 각 항목을 하나씩 두고, 마지막 항목에 쉼표를 넣습니다.


    // bad
    function foo(bar,
                 baz,
                 quux) {
      // ...
    }
    
    // good
    function foo(
      bar,
      baz,
      quux,
    ) {
      // ...
    }
    
    // bad
    console.log(foo,
      bar,
      baz);
    
    // good
    console.log(
      foo,
      bar,
      baz,
    );

화살표 함수 (Arrow Functions)

  • 7.1 (인라인 콜백을 전달할 때 같이) 익명함수를 사용할 때는 화살표 함수 표현을 사용하세요.


    why? 화살표 함수는 그 컨텍스트의 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;
    });

  • 7.2 하나의 식으로 구성된 함수가 사이드 이펙트 없는 표현식을 반환하는 경우, 중괄호를 생략하고 암시적 반환을 사용할 수 있습니다. 그 외에는 중괄호를 그대로 두고, return문도 사용하세요.


    why? Syntactic sugar이기 때문입니다. 여러 함수가 연결된 경우 읽기 쉬워집니다.

    // 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
    foo(() => bool = true);
    
    // good
    foo(() => {
      bool = true;
    });

  • 7.3 명확성과 일관성을 위해 항상 인자를 괄호로 감싸세요.


    why? 인자를 추가하거나 제거할 때 변경 사항을 최소화할 수 있습니다.

    // 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;
    });

  • 7.4 화살표 함수 구문(=>)과 비교 연산자(<=, >=)를 헷갈리게 하지 마세요.


    // 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;
    };

  • 7.5 암시적 반환을 하는 화살표 함수 몸체의 위치를 적절히 설정하세요.


    // bad
    (foo) =>
      bar;
    
    (foo) =>
      (bar);
    
    // good
    (foo) => bar;
    (foo) => (bar);
    (foo) => (
       bar
    )

클래스 & 생성자 (Classes & Constructors)

  • 8.1 클래스는 생성자가 명시되지 않은 경우 기본 생성자를 갖습니다. 빈 생성자 함수나 부모 클래스로 위임하는 함수는 불필요합니다.

    // bad
    class Jedi {
      constructor() {}
    
      getName() {
        return this.name;
      }
    }
    
    class Rey extends Jedi {
      constructor(...args) {
        super(...args);
      }
    }
    
    // good
    class A { }
    
    class A {
        constructor () {
            doSomething();
        }
    }
    
    class B extends A {
        constructor() {
            super('foo');
        }
    }
    
    class B extends A {
        constructor() {
            super();
            doSomething();
        }
    }

  • 8.2 중복되는 클래스 멤버를 만들지 마세요.


    why? 중복된 클래스 멤버를 선언하면 암묵적으로 마지막 멤버가 적용됩니다. 중복은 확실히 버그입니다.

    // bad
    class Foo {
      bar() { return 1; }
      bar() { return 2; }
    }
    
    // good
    class Foo {
      bar() { return 1; }
    }
    
    // good
    class Foo {
      bar() { return 2; }
    }

  • 8.3 클래스 메소드는 외부 라이브러리나 프레임워크가 구체적으로 비정적 메소드를 요구하지 않는 이상 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');
      }
    }

모듈 (Modules)

  • 9.1 같은 경로는 한 곳에서 import하세요.


    why? 같은 경로에서 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';

  • 9.2 가변 바인딩을 export하지 마세요.


    why? 변조는 일반적으로 피해야 하지만, 가변 바인딩을 export할 때는 특히 그렇습니다. 이 기술이 어떤 특별한 상황에 필요할 수도 있지만, 일반적으로는 상수 참조만 export되어야 합니다.

    // bad
    let foo = 3;
    export { foo };
    
    // good
    const foo = 3;
    export { foo };

  • 9.3 한가지만 export하는 모듈에서는 이름 붙여진 export보다는 default export를 사용하세요.


    why? 하나만 export하는 파일의 가독성과 유지보수성이 더 좋기 때문입니다.

    // bad
    export function foo() {}
    
    // good
    export default function foo() {}

  • 9.4 모든 import구문을 다른 구문들 위에 두세요.


    why? import구문은 호이스트되기 때문에 이것을 가장 위에 두면 예상치 못한 결과를 막을 수 있습니다.

    // bad
    import foo from 'foo';
    foo.init();
    
    import bar from 'bar';
    
    // good
    import foo from 'foo';
    import bar from 'bar';
    
    foo.init();

  • 9.5 여러 줄에 걸친 import는 여러 줄의 배열이나 객체 리터럴처럼 들여쓰기하세요.


    why? 스타일 가이드에 있는 다른 모든 중괄호 블록들 처럼 중괄호는 같은 들여쓰기 규칙을 따릅니다. 콤마가 그렇듯이 말이죠.

    // bad
    import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
    
    // good
    import {
      longNameA,
      longNameB,
      longNameC,
      longNameD,
      longNameE,
    } from 'path';

  • 9.6 모듈 import 구문에서 Webpack loader 구문을 사용하지 마세요.


    why? 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';