Home > database >  Can i spread an Array of parameter names into a function declaration
Can i spread an Array of parameter names into a function declaration

Time:10-16

I have an object which returns,

[
    {
        name:"getSpeed",
        params:["distance","time"]
    },
    {
        name:"getTime",
        params:["speed","distance"]
    },
    ...
]

This object is subject to change as it is gathered from an embedded device.

im trying to convert this into an object with callable functions i.e.


let myObj = {
    getSpeed: function(distance, time){
        /* do something (this is irrelevant) */
    },
    getTime: function(speed, distance){
        /* do something (again not relevant) */
    }

}

is there any way to map an array of strings to function parameters when mapping over an array?

CodePudding user response:

According to your comments it appears you want to create functions from this definition which send commands with a function-call-like string which is evaled on the other side, and you don't actually care about the paramater names but rather about the correct number of parameters.

I would therefore recommend something like this:

const myObj = Object.fromEntries(data.map(({ name, params }) => [
  name,
  (...args) => {
    if (args.length !== params.length) {
      throw new TypeError(`${name} expected ${params.length} arguments, got ${args.length}`)
    }
    
    this.UART.write(`${name}(${args.map(arg => JSON.stringify(arg)).join(',')})`)
  }
]))

This will work with all the datatypes that JSON supports, and will as a side effect also pass undefined as argument correctly.

Here is a runnable example with console.log instead of this.UART.write:

const data = [
    {
        name: "getSpeed",
        params: ["distance", "time"]
    },
    {
        name: "getTime",
        params: ["speed", "distance"]
    }
]


const myObj = Object.fromEntries(data.map(({ name, params }) => [
  name,
  (...args) => {
    if (args.length !== params.length) {
      throw new TypeError(`${name} expected ${params.length} arguments, got ${args.length}`)
    }

    console.log(`${name}(${args.map(arg => JSON.stringify(arg)).join(',')})`)
  }
]))

myObj.getSpeed(123, 456) // prints `getSpeed(123,456)`
myObj.getTime(123, 456) // prints `getTime(123,456)`
myObj.getTime("hello", true) // prints `getTime("hello",true)`
myObj.getTime(1) // throws `getTime expected 2 arguments, got 1`

However, as you said yourself, the whole eval business is not ideal anyway. I would recommend - if possible - to reconsider the protocol to use something more secure and robust like gRPC or, one layer below, protocol buffers. Given that you are using JavaScript on both ends, JSON-RPC could also be a nice solution.

  • Related