Functions with optional parameters

von Jan Hansen (Kommentare: 0)

Today we are having fun refactoring legacy code. In our application there are  functions with various optional parameters.

callRequest(method, params, data, headers, url)

Only method is mandatory, all other parameters are optional. The status quo consists of each parameter being checked for existance, not very pretty...

callRequest(method, params, data, headers, url) {
    if (headers && headers.length > 0) { 
        ... 
    }
    ...
}

What can we improve? The java developper would use different function signatures but that doesn't work in javascript. We can however rearrange the order of the parameter and put the optional parameters last. Thus we can omit them like this:

callRequest('GET', {data:'memberId'},
    null, null, null);
callRequest('GET', {data:'memberId'});

But in our specific case we needed all possible combinations of parameters. Sometimes only method and params were set, sometimes only method and data. So this approach does not work here.

callRequest('GET', {data:'memberId'}, 
    null, null, "url/to/somwhere");

What do we do? Default parameter from ES6! New signature:

callRequest(method, params = {}, data = {}, 
    headers = [], url = this.get('url')) {
    ...
}

So we can omit the non used parameters! Well, as a matter of fact, we cannot as the ordering of the parameters is still important. We still have to pass the full number of parameters

callRequest('GET', {data:'memberId'}, 
    null, null, "/url/to/the/treasure");

but we can leave out the if statements as the third parameter is now garantied to be an object, right? No, see Mozilla

Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed.

So this works if we omit some parameters alltogether but not for our specific problem. We could do something like

callRequest('GET', {data:'memberId'}, 
    undefined, undefined, "url/to/somwhere");

But no, just no. We don't want to do that and neither does eslint. So, what else? What kind of data structure has members that can be omitted? How about an object? Object properties can be omitted so we try that approach. New signature:

callRequest(method, {
    params: params = {},
    data: data = {},
    headers: headers = [],
    url: url = this.get('url')
}) {
    ...
} 

How do we acess the parameters now? We can use Object destructuring and just access them directly:

callRequest(method, {params: params = {}, 
    data: data = {}, 
    headers: headers = [], 
    url: url = this.get('url')}) {

    // This is safe now, 
    // as headers is always an array.
    if (headers.length > 0) {
        ...
    }
}

Now we can call the function and omit the unused parameters! New call:

callRequest('GET', {params: {data:'memberId'}, 
    url: "portfolio/"});

Zurück