0

In Javascript, I would like to create a variable (primitive or object) that can also be invoked as a function.

The desired result is:

console.log(myVar) // Outputs some variable previously defined
console.log(myVar()) // Outputs the result of some previously defined function

I would like the variable used to be exactly the same. For example, I do not want:

const myVar = () => 1;
myVar.prop = 2;

I have tried overriding both the Object.prototype.toString and Object.prototype.valueOf functions, but each need to be manually invoked:

const myVar = () => 1;
myVar.toString = () => 2;
console.log(myVar + myVar) // This outputs 4, thanks to coercion
console.log(typeof myVar) // Outputs function, want 'number' in this example

My use case for this is the following scenario, where the result of someFunction(payload) acts as both a value and a function.

someFunction(payload)(options) // Result depends upon payload and options, returns a value
someFunction(payload) // Options is not specified, returns a value
someFunction(payload, options) // Would prefer not to use this method

In the desired use case, I'd like someFunction(payload) to act as an alias for someFunction(payload)(). I tried:

const someFunction = payload => {
    const innerFunction = options => {
        // Return value depending on payload and, if it exists, options
    };
    innerFunction.toString = () => innerFunction();
    return innerFunction;
};
console.log(someFunction(payload)(options)) // A value, correct
console.log(someFunction(payload)) // A function, do not want

I also tried using a combination of calling toString and eval (to executed the stringified function) to trigger the toString(), but could not get it to work.

Nysor
  • 38
  • 2
  • 6
  • 1
    Possible duplicate of [Can you make an object 'callable'?](https://stackoverflow.com/questions/19335983/can-you-make-an-object-callable) – Etheryte May 23 '19 at 01:57
  • I think it's the worst of ideas to rot code. – Mister Jojo May 23 '19 at 02:22
  • @Kaiido The "value" in my example is just some primitive or object that is returned by innerFunction. My question boils down to is if there is a way to have an optional function call after a function, e.g. someFunction(payload)() ?= someFunction(payload). – Nysor May 23 '19 at 02:26
  • 1
    If it is a primitive, then you can set the `fn[Symbol.toPrimitive]` of your function object, however, this will only work when you'll do operations like "a + fn". If it is an object, then your function already is one. And in any case, you won't be able to change the `typeof` return value, and this would be unreadable to anyone. – Kaiido May 23 '19 at 02:31

1 Answers1

1

So I'm not entirely sure I understand the "why" of this question, but I am going to give this a shot.

What you could do is create a data type and have it return a default value and then when you use the "new" constructor you could then get access to its values like the function.

So if you see in the below image I created a function and have values that could be used if I constructed the data type, however if I am just invoking the function I am able to return a value instead.

If you use the constructor of the function and create a instance of this data type you can then just manipulate the value directly.

I dont think that totally gets you to where you want, but I am hoping it gets you a little closer.

   function Payload(val, options) {
     this.innerFunction = () => { console.log(options)}
     this.value = val
     return val
    }
    console.log(Payload(10, {key:"KEY" })) // print 10
    console.log(typeof Payload(10, {key:"KEY" })) // number
    x = new Payload(10, {key:"KEY" })
    x.innerFunction() // returns {key:"KEY" }
    x.val // returns 10
Grant Herman
  • 923
  • 2
  • 13
  • 29