보통 JavaScript function을 작성하다 보면, 경우에 따라 딱히 정해져 있지 않은 수의 parameters를 받아서 처리해야 할 때가 있다. 이럴 땐, 아래 코드처럼 전달된 각 parameter의 타입을 확인해서 전달받지 못한 놈은 미리 정해진 기본값을 지정해서 사용하는 패턴이 많이 쓰인다.

function foo(ab) {
  a = typeof a !== 'undefined' ? a : 'default_a';
  b = typeof b !== 'undefined' ? b : 'default_b';
  ...
}

이런 사용 패턴의 쓰임새가 점점 늘어남에 따라, ECMAScript 6에선 parameters에 default values를 아주 쉽게 지정할 수 있는 용법이 제안되었는데, 그 사용 예를 들면 다음과 같다.

/* ECMAScript 6에 포함된 Default Function Parameters */
function multiply(ab = 1) {
  return a * b;
}
 
multiply(5); // 5 

참고로, ES6의 default function params 웹브라우저 지원 상황을 보면, Firefox(v.15 이상)에서만 지원해서 아직 실제로 사용하기엔 이른 아쉬움이 있다.

그런데 이렇게 function에 전달할 parameters의 개수가 가령 세 개 이상으로 늘어나면 이에 대응하는 각 parameter의 타입을 확인하는 과정도 늘어날 수밖에 없고, 또 전달된 parameters의 순서도 그 결과 값에 중대한 영향을 미치게 된다. 이는 실제 function 사용 시 parameter의 순서를 착각해서 다르게 전달한다면 커다란 문제를 일으키게 될 소지가 있으므로 주의해야 한다.

그래서, 이와 같은 사용의 번거로움과 실수를 방지하려고 전달할 parameters의 수가 많을 땐 다음과 같이 function parameter로 하나의 options object를 받아서 구현하는 방법도 널리 쓰이고 있다.

function fooWithOptionsObject(options) {
  options = options || {};
  var defaults = {option1: 'default_1', option2: 'default_2', option3: 'default_3'};
 
  for (var prop in defaults)  {
    options[prop] = typeof options[prop] !== 'undefined' ? options[prop] : defaults[prop];
  }
  console.log(options.option1, options.option2, options.option3);
}
 
var params = {option1: 'myOption_1', option2: 'myOption_2'};
fooWithOptionsObject(params);
// → myOption_1 myOption_2 default_3 

이렇게 하면, 함수를 쓸 때마다 전달 parameters의 순서를 신경 쓸 필요없이 그냥 지정하고 싶은 parameter의 값을 해당 object key의 value에다 심어서 전달해주면 되고, 나머진 자동으로 default 값이 지정되는 장점이 있다.

한편, 위 함수의 parameter로 전달된 options object에 적용된 과정을 살펴보면, 원래의 object와 또 하나의 기준 object를 비교해서 원래 전달된 object에 정의되지 않은(undefined) properties를 기준 object의 것으로 채워서 다시 원래의 object를 되돌려주는 것이라 볼 수 있는데, 이와 같은 기능은 대표적인 jQuery.extend() method와 더불어 일반 다목적 utilities function library인 Underscore.jsLo-Dash에서도 _.defaults라는 이름의 함수를 다 같이 제공하고 있으며 각각의 사용법은 다음과 같다.

var defaults = { validate: false, limit: 5, name: 'foo' };
var options = { validate: true, name: 'bar' };
 
$.extend({}, defaults, options);
_.defaults(options, defaults);
// →  { validate: true, limit: 5, name: 'bar'} 

JavaScript function parameter overloading 만세~!
용량을 초과해버린 짐차. 달리는 게 신기할 지경.
우연히도 JavaScript 관련 글을 올리면서 JavaScript의 18번째 생일을 맞이하게 되었군.
JavaScript가 점점 강력해지는 엔진을 달고서 어디까지 쭉쭉 내달리지 앞으로가 더 기대되는 시점이다.

관련된 주제의 글

댓글을 남겨 주세요