音の鳴るブログ

鳴らないこともある

JavaScript の関数にデフォルト引数をつける 2

JavaScriptPython のような辞書でも指定できるデフォルト引数をつける試み、 昨日 のは駄目だった。 コメントに引数情報を書くと未来永劫ミニファイできなくなる。ちょっとふざけすぎたと反省して、というか使い物にならないので書き直した。

fn という関数で対象となる関数のオプションを指定してビルドする方式にした。オプションと言ってもデフォルト引数しか用意していないけど、頑張ればマクロ展開みたいなのも出来るかも知れない。

https://gist.github.com/mohayonao/5944952

デフォルト引数は数値のみで考えています。

使い方

var madd = fn(function(val, mul, add) {
  return val * mul + add;
}).defaults("val=0,mul=1,add=0").build();

assert.equal(10, madd(10));
assert.equal(20, madd(10, 2));
assert.equal(30, madd(10, {add:20}));

コード

var fn = (function() {
  function Fn(func) {
    this.func = func;
    this.def  = [];
  }
  Fn.prototype.defaults = function(def) {
    this.def = def;
    return this;
  };
  Fn.prototype.build = function() {
    var func = this.func, def = this.def.split(","), keys = [], vals = [];
    for (var i = 0, imax = def.length; i < imax; ++i) {
      var items = def[i].trim().split("=");
      keys.push(items[0].trim());
      vals.push(items.length === 1 ? 0 : +items[1]);
    }
    return function() {
      return func.apply(this, args_resolution(keys, vals, slice.call(arguments)));
    };
  };
  var slice = Array.prototype.slice;
  var isDictionary = function(obj) {
    return !!(obj && obj.constructor === Object);
  };
  var args_resolution = function(keys, vals, given) {
    var dict, args = vals.slice();
    if (isDictionary(given[given.length - 1])) {
      dict = given.pop();
      for (var key in dict) {
        var index = keys.indexOf(key);
        if (index !== -1) {
          args[index] = dict[key];
        }
      }
    }
    for (var i = 0, imax = Math.min(given.length, args.length); i < imax; ++i) {
      args[i] = given[i];
    }
    if (dict) { args.push(dict); }
    return args;
  };
  return function(func) { return new Fn(func); };
})();