Saturday, 19 December 2020

Extract Parameter Names in JavaScript

After publishing my previous post I realised there was a nice way to improve my "joinCollections" funtion, getting rid of the 2 "alias" parameters. First let's see the code again:


function joinCollections(collection1, collection2, idSelectorFn1, idSelectorFn2, alias1, alias2){
    let result = [];
    collection1.forEach(it1 => {
        let id1 = idSelectorFn1(it1);
        collection2.forEach(it2 =>{
            if (id1 === idSelectorFn2(it2))
                result.push({
                    [alias1]: it1,
                    [alias2]: it2
                });
        });
    });
    return result;
}

let persons = joinCollections(employees, 
    students, 
    employee => `${employee.firstName}-${employee.lastName}`, 
    student => `${student.firstName}-${student.lastName}`,
    "employee",
    "student"
)

As you can see we are using the same value as "alias" and as the parameter name in the selector funtion. Of course we could have done differently (employee/emp...), but there's not any reason for that. The alias and the parameter refer to the same thing, whatever thing we have stored in the collection.
In JavaScript we can get access to the parameter names of a function just by converting the function to string and extracting the names from the function signature. Hence, we can easily extract the alias from the selector function, just like this (code specific for an arrow function)
selectorFn.toString().split("=>")[0].trim();


function joinCollections2(collection1, collection2, idSelectorFn1, idSelectorFn2){
    let getAlias = selectorFn => selectorFn.toString().split("=>")[0].trim();
    let [alias1, alias2] = [idSelectorFn1, idSelectorFn2].map(getAlias);

    let result = [];
    collection1.forEach(it1 => {
        let id1 = idSelectorFn1(it1);
        collection2.forEach(it2 =>{
            if (id1 === idSelectorFn2(it2))
                result.push({
                    [alias1]: it1,
                    [alias2]: it2
                });
        });
    });
    return result;
}

let persons = joinCollections(employees, 
    students, 
    employee => `${employee.firstName}-${employee.lastName}`, 
    student => `${student.firstName}-${student.lastName}`
)

The call to joinCollections is now much cleaner.

This post has made me think again about the difference between arguments and parameters. It's perfectly explained here:

A parameter is the variable which is part of the method’s signature (method declaration). An argument is an expression used when calling the method

If you check the comments there's one question that also came to my mind, the array-like object arguments that we have inside javascript functions, shouldn't it have been called parameters?

No, it should not. That object gives us access to what the funcion has been passed/has received in that invocation, not to the list of parameters in its signature. The signature can have x parameters and we can pass over "y" values. arguments gives us access to those "y" values.

No comments:

Post a Comment