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?
edit: I should note that the requirements are:
- to not use global scope (outside of the function)
- we must retrieve the arguments through func.toString()
2
Answers
Do not rely on
func.toString()
. As you’ve demonstrated yourself, there are many ways in which this can and does break; it is not a generally solvable problem. Parameter names are an implementation detail and should be considered unreliable.Instead, have your function accept an object with named properties, you can easily merge those:
With this, your test cases work:
A solution could be to maintain a registry of functions that are returned by
defaultMethod
. In your example it would register the functionadd_
and the parameter names. Then ifdefaultMethod
is called with that function as argument, you can find it in the registry and learn about the parameter names.So the code would change like this: