javascriptclassoperator-overloadinginstance

In js, is there any feature can implement callable instance, like __call__ method in python


In python, you can make an instance become a callable obj, like below shows:

# py code snippet

class Demo:
    def __call__(self):
        print("Demo's instance callable")

Demo()()  # Demo's instance is callable

In js, is there the same feature like shown above?

// js code snippet

function Demo1() {}
const d1 = new Demo1();

class Demo2 {}
const d2 = new Demo2();

// can I make d1 or d2 become a callable instance? like d1() or d2() to run some function logic.

Another question:
What property or feature on Function or Function.prototype, make it's instance is callable? Since I cant find any point of it on MDN Function page


Solution

  • You can not do that. But you can achieve something like that...

    Here's my recommendation:

    // Define your object with as many properties as needed.
    const AnyObject =
    {
      get Myself ()
      {
        return this;
      }
    };
    
    // Define a callable function which can't be arrow function if you
    // want to use the this keyword pointing to the defined object.
    const UnboundCallable = function ()
    {
      console.log('The value of this.Myself is:', this?.Myself);
    }
    
    // Define a bound callable which points the this keyword to itself.
    const BoundCallable = UnboundCallable.bind(UnboundCallable);
    
    // Set your defined object as the prototype of the unbound callable.
    Reflect.setPrototypeOf(UnboundCallable, AnyObject);
    
    // Set your defined object as the prototype of the bound callable.
    Reflect.setPrototypeOf(BoundCallable, AnyObject);
    
    // You'll actually use the BoundCallable which behaves the best like
    // you intend it to.
    
    // You can also do this:
    class Demo
    {
      get Myself ()
      {
        return this;
      }
      
      constructor ()
      {
        const UnboundCallable = function CallableDemoObject ()
        {
          console.log('The value of this.Myself is:', this?.Myself);
        }
        
        const BoundCallable = UnboundCallable.bind(UnboundCallable);
        
        Reflect.setPrototypeOf(UnboundCallable, this);
        Reflect.setPrototypeOf(BoundCallable, this);
        
        return BoundCallable;
      }
    }
    
    ///// TESTS /////
    
    const MyDemo = new Demo;
    
    MyDemo();
    // Outputs:
    // The value of this.Myself is:  [object Function]
    
    console.log( MyDemo.Myself );
    // Outputs:
    // [object Function]
    
    console.log( MyDemo.name );
    // Outputs:
    // bound CallableDemoObject
    
    console.log( 'MyDemo is instance of Demo?', MyDemo instanceof Demo );
    // Outputs:
    // MyDemo is instance of Demo? true
    
    console.log( 'MyDemo is instance of Function?', MyDemo instanceof Function );
    // Outputs:
    // MyDemo is instance of Function? false
    
    console.log( 'Type of MyDemo:', typeof MyDemo );
    // Outputs:
    // Type of MyDemo: function
    
    console.log( 'UnboundCallable is instanceof Function?', UnboundCallable instanceof Function );
    // Outputs:
    // UnboundCallable is instanceof Function? false
    
    console.log( 'Type of UnboundCallable:', typeof UnboundCallable );
    // Outputs:
    // Type of UnboundCallable: function
    
    UnboundCallable();
    // Outputs:
    // The value of this.Myself is: undefined
    
    // The above happens because the this keyword inside the function is
    // the actual context of the variable that reference the function.
    // In Node, if in top level then the this keyword will be undefined.
    // In any case, it will return anything other than undefined if the
    // referenced value in this has Myself.
    
    console.log( UnboundCallable.Myself );
    // Outputs:
    // [object Function]
    
    // The above happens because even if the function is unbound, its
    // prototype is still AnyObject. Myself is a getter that returns
    // the this value which points to the function itself.
    
    BoundCallable();
    // Outputs:
    // The value of this.Myself is: [object Function]
    
    // The above happens because the function is bound and its this
    // keyword points to itself. As the function have the AnyObject
    // as its prototype, its Myself getter will return this which
    // points to the function itself.
    
    console.log( BoundCallable.Myself );
    // Outputs:
    // [object Function]
    
    // The above happens because even if the function is bound and its
    // prototype is still AnyObject. Myself is a getter that returns
    // the this value which points to the function itself.
    
    console.log( BoundCallable.name );
    // Outputs:
    // bound UnboundCallable

    You'll actually use the BoundCallable as your object which behaves the best like you intend it to.

    NOTE: As the generated function object prototype is a prototype of an object and not a function, then BoundCallable and CallableDemoObject don't pass the test instanceof Function, but they're still function in a typeof statement.