Creating Callable Objects in JavaScript

Tram Ho

Article translated from source: https://hackernoon.com/creating-callable-objects-in-javascript-d21l3te1

Callable object are data structures that act as both object and function . You can access and assign the obj.bar property, call obj.foo () , call obj () , as if it were a function .

Direct calling is like calling an obj function that changes the properties of an object through context .

If you have experience with Python , you will realize this, there is a built-in Python protocol using the __call__ class method . Any method assigned to __call__ can be called obj.__call __ () or obj() .

Callable Objects can also be considered stateful function . Functions are inherently instance statless procedures .

In JavaScript almost everything is an object , including functions, so we can certainly do this, but how? It is not built into a language like Python , but there are several ways to make it work.

The Challenge

Inspired by Python , create a Class constructor that can be used to create _call objects to redirect to a method named _call . This redirection makes it possible to inherit from the Class and easily override and extend _call method with the new functionality, without having to worry about the inner operation of the _call object.

To do this, we will need to inherit from the Function constructor, inherit from the Object and allow creation of both object and dynamic function .

The main obstacle is giving a function object that references itself.

To have a reference to the __call method , the function part of the function object created by the Callable class constructor must have a reference for itself.

The Solutions

Creating an extensible Callable class maintains proper and correct inheritance in JavaScript and allows calling objects that it constructs to function, with references to themselves, redirecting to the overridable method _call .

Because inheriting from Function , it is possible to create dynamic function from string , using super in the constructor. So, the string being passed to super will be the body of fucntion . That Fucntion can access its own object and call a _call method, passing its argument . Do this by using bind .

Bind method will set this context of a function for whatever we want, by wrapping that function in a bound function. So bind the function to itself by this.bind(this) .

Callable object has a reference to itself, except the object returned from the constructor , returned by this . So all the properties will be appended to it, our function has a reference to the old object passed to bind .

An easy solution to this problem is to attach a reference to the new object wrapped on the old object by _bound . And the body of the function , in the string going to super , just call _call , using this._bound reference .

The Callee Way

Again use super call to create a dynamic function, which is referenced to the function itself by taking advantage of another hidden variable within a function.

The argument object with argument.callee is a reference to the called function. Use this reference as the first argument to link functions.

So inside the function body, the string is passed to super , just call _call in arguments.callee .

The Closure & Prototype Way

Here instead of creating a dynamic function with siêu , we remove the function object created by the constructor ( this object ) and replace it with closure , by returning instead of this from the constructor .

closure is also a function object and can reference itself in the body via the closure variable. Use reference closure to redirect the call to its __call method.

But we broke the string by replacing this with closure , and re-attaching the constructor ‘s prototype to closure using Object.setPrototypeOf and new.target (which is a reference to the constructor) to get the prototype .

You can use this.constructor.prototype instead of new.target.prototype . But when calling the first time to create the object , it is quite meaningful.

The Proxy Way

Using Proxy, we can block calls to fucntion , using apply , and redirect it to another function. The apply allows to call it a reference to itself as the target argument .

So we created a Class that inherits Fucntion , Callable , packages Fucntion objects created in a Proxy , any calls made to those objects and redirects them to _call function on the object itself. , use target .

Thanks and hope the article is useful in your work.

Share the news now

Source : Viblo