6. Functions (JS style guide)

코비코 koreanvisionarycoder ㅣ 2022. 12. 14. 16:54

함수 표현식보다는 함수 선언식을 활용한다.  eslint : func-style


 

Use function declarations instead of function expressions

 

  • 함수 표현식(=함수식)보다는 함수 선언문을 활용한다.
  • 함수 선언문은 파일에서 함수가 정의되기 전에 함수를 참조할 수 있다.
  • 함수 선언문은 함수 본체까지 호이스팅 되지만, 함수 표현식은 참조(함수 이름)만이 호이스팅 된다. 이 룰에 의해 함수식의 부분을 항상 Arrow함수에서 이용하는것이 가능하다.
  • 함수 선언문은 함수의 정의가 파일의 나머지 부분을 이해하기 어려울 만큼 복잡하다면 모듈로 추출할 수 있다.
// bad
function foo() {
  // ...
}

// bad
const foo = function () {
  // ...
};

// good
// 변수 참조 호출과 구분되는 이름
const short = function longUniqueMoreDescriptiveLexicalFoo() {
  // ...
};

 

 

 

 

즉시 호출 함수 표현식을 괄호로 감싸기 eslint: wrap-iife


  • 즉시 호출 함수 표현식은 하나의 단위이며, 괄호로 이것을 감싸면 괄호 안의 표현을 명확하게 해준다.
  • 모듈을 어디에서나 사용한다면 즉시 호출 표현식은 전혀 필요하지 않다는 점을 주의 해야한다.
// 즉시 호출 함수 표현식 (IIFE)
(function () {
  console.log('Welcome to the Internet. Please follow me.');
}());

 

 

 

 

 

비함수블럭에서 함수 선언 X -> 변수에 함수 할당.

eslint: no-loop-func


 

 Never declare a function in a non function block (if, while, etc).  Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears.

  • non-function block : if, while, etc
  • if, while 등의 블록 내부에서 함수를 선언하지 않습니다.
  • (if, while, etc). 브라우저마다 함수 block의 해석을 다르게 허용할 것이다

 

 

 

 

매개변수에 arguments 사용 X


Never name a parameter arguments. This will take precedence over theargumentsobject that is given to every function scope.`

  • arguments 라는 이름을 갖는 파라미터를 사용하지 않습니다. 이는 함수 스코프 내에 주어지는 arguments라는 오브젝트를 덮어 쓰게 된다.
  • 함수의 arguments 프로퍼티보다 매개변수의 arguments 가 우선시 된다.
// bad
function nope(name, options, arguments) {
  // ...stuff...
}

// good
function yup(name, options, args) {
  // ...stuff...
}

// 참고: arguments란?
/* 함수의 매개변수 목록을 가져오는 예약 변수
let what_is_arguments = function(a, b, c) {
  console.log(arguments);
}

what_is_arguments(1, 2, 3); // { 0: 1, 1: 2, 2: 3 }
*/

 

 

prefer-rest-params : rest syntax ... > arguments X


Never use arguments, opt to use rest syntax ... instead.

  • 함수 파라미터의 arguments 대신 rest 파라미터인 ...를 사용합니다.
  • ... 을 사용하는 것이 더 명시적이며, Array-like인 arguments 와 달리 ...은 진짜 Array이다.
// bad
function concatenateAll() {
  const args = Array.prototype.slice.call(arguments);
  return args.join('');
}

// good
function concatenateAll(...args) {
  return args.join('');
}


// example
function aFunc(...args) {
  console.log(arguments);
  console.log(args);
}

aFunc(1, 2, 3);

/* 실행 결과
{ 0: 1, 1: 2, 2: 3 } // Array-like Object
[ 1, 2, 3 ] // Array
*/

 

 

default parameter syntax > 함수 인자 변경


Use default parameter syntax rather than mutating function arguments.

  • 함수의 파라미터를 변경하는 것 보다, default 파라미터를 사용합니다.
// really bad
function handleThings(opts) {
   // 절대 함수의 인자를 변경해선 안된다.
  // opts 가 거짓이면 원하는 객체로 설정되지만 미묘한 버그가 발생할 수 있습니다.

  opts = opts || {};
  // ...
}

// still bad
function handleThings(opts) {
// 여전히 파라미터를 조건적으로 변경시키는 코드입니다.
  if (opts === void 0) {
    opts = {};
  }
  // ...
}

// good
function handleThings(opts = {}) {
  // ...
}

 

 

사이드 이펙트를 유발하는 default parameter 사용 않을 것.


Avoid side effects with default parameters.

  • 사이드 이펙트가 있을만한 default 파라미터는 사용하지 않는다.
  • 이러한 파라미터는 가독성면에서 혼란을 줄 수 있다.
var b = 1;
// bad
function count(a = b++) {
  console.log(a);
}
// default 파라미터에 후위 연산자를 사용함으로써 실행시 console.log에 의해 노출될 값을 예측하기 어렵다.
count();  // 1
count();  // 2
count(3); // 3
count();  // 3

 

 

default-param-last : default parameters 는 마지막에 적어줌.


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

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

 

 

ECMA-262, block as statements(명령문),

함수선언 as not statements .


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

// bad
if (currentUser) {
  function test() {
    console.log('Nope.');
  }
}

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

 

 

 

No-new-func : 함수 객체 생성, 함수 생성자 X.


Never use the Function constructor to create a new function.

  • 절대 새 함수를 작성하기 위해 Function constructor를 이용하지 마십시오
  • 문자열을 'eval()' 와 유사하게 평가한다.
  • 취약점
// bad
var add = new Function('a', 'b', 'return a + b');

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

// good
var x = function (a, b) {
    return a + b;
};

 

 

space-before-function-paren, space-before-blocks : 함수 시그니처의 space 유지


  • functions 그리고 methods 의 입력과 출력을 정의
  • parameters와 그들의 types
  • 반환값과 타입
  • 던져지거나 콜백으로 반환되는 exceptions
  • object-oriented 프로그램에서 메소드의 접근 권한에 대한 정보 (* public, static, 혹은 prototype와 같은 키워드들).
  •  
  • 일관성
  • 이름 추가/제거 -> 공백 추가/제거 의 동작을 안해도됨.
// bad
const f = function(){};
const g = function (){};
const h = function() {};
const a = function a() {};

// good
const x = function () {};
const y = function a() {};

 

 

No-param-reassign : 매개 변수로 전달 된 객체 조작 금지


  • 함수의 (original)caller 에게 변수 부작용의 가능성이 있다.
// bad
function f1(obj) {
  obj.key = 1;
}

// good
function f2(obj) {
  const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
}

 

 

No-param-reassign : 매개변수 재할당 금지


  • 매개변수 재할당
    • arguments 객체 접근 -> 예측할 수 없는 결과를 불러 일으킨다.
    • 최적화 이슈, especially in 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) {
  // ...
}

 

prefer-spread : 가변 함수, spread operator ... > apply


  • variadic functions (가변 함수)
    • 가변 개수의 인수 허용
  • apply 메서드로 context(this) 를 제공해 줄 필요 없어 깨끗하다.
  • apply 메서드를 한번 더 적용하기 힘들다.
// bad
const x = [1, 2, 3, 4, 5];
console.log.apply(console, x);

// good
console.log(...x);

// bad
new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));

// good
new Date(...[2016, 8, 5]);

var args = [1, 2, 3, 4];

// bad
Math.max.apply(Math, args);

// good
Math.max(...args);