Function that receives a function and a “default parameters” key-value object and returns another function with default arguments set

That sounds kind of complex. The idea here is to write the method “defaultMethod”. It receives a function and an object. If the function is a simple add:

function add(a,b) { return a+b;};

When calling

var add_ = defaultMethod(add,{b:9});
add_(10)

The behavior is:

  • default value for a: undefined
  • default value for b: 9
  • received value for a: 10
  • received value for b: undefined

and the return must be 19.

The catch is that the method can be called more than once:

var add_ = defaultMethod(add,{b:9}); // set 'b' default value as 9
    add_ = defaultMethod(add_,{b:3, a:2}); // now, set 'b' default value as 3 and 'a' as 2
    let res = add_(10) //sent 'a' value as 10
    expect(res).toBe(13); //10 (received) + 3 (default) 

I wrote it like this:

function defaultMethod(func, params) {
    var funcStr = func.toString();
    let requiredArgs = funcStr
      .slice(funcStr.indexOf('(') + 1, funcStr.indexOf(')')) //get the between parenthesis part
      .match(/([^s,]+)/g) || []; //resulting in ['a', 'b']

    console.log(requiredArgs)
  
    return function (...args) {
      let calledArgs = args;
  
      if (calledArgs.length < requiredArgs.length) {
        for (let i = calledArgs.length; i < requiredArgs.length; i++) {
          if (calledArgs[i] === undefined) {
            calledArgs[i] = params[requiredArgs[i]];
          }
        }
      }
  
      return func(...calledArgs);
    };
  }
  

It works well for one calling, for example, all of these unit tests passes:

var add_ = defaultMethod(add,{b:9});

it('should return 19', () => {
    expect(add_(10)).toBe(19);
})

it('should return 17', () => {
    expect(add_(10,7)).toBe(17);
})

it('should return nan', () => {
    expect(add_()).toBe(NaN);
})

Although, when we call the defaultMethod one more time, now passing the add_ function, it starts to break. The console.log(requiredArgs) starts to log [...args] instead of ['a', 'b'].

The unit tests are the following:

var add_ = defaultMethod(add,{b:9}); // set b default value as 9
    add_ = defaultMethod(add_,{b:3, a:2}); // now, set b default value as 3 and a as 2

it('should return 13', () => {
    expect(add_(10)).toBe(13); //10 (received) + 3 (default) 
})//this one breaks returning 19

it('should return 5', () => {
    expect(add_()).toBe(5);
})//this one breaks returning NaN

it('should return nan', () => {
    add_ = defaultMethod(add_,{c:3}); // this doesn't do anything because c isn't required
    expect(add_(10)).toBe(NaN);
})//this one breaks returning 19

And I can’t figure a way to make it work for more than one calling. Apparently, GPT-4 neither. Any ideas?