How can a value be invoked (as a function) at the same time as it contains properties (as an object) in Javascript?

Asked

Viewed 60 times

3

I was left with a question concerning the structure of the Express.

How Express can be invoked, as in express(), but can also have in its structure access to the Router property, for example?

I don’t know if my doubt was clear, so I’ll try to illustrate. To create a structure with access to a name method Router, for example, just create an object and set a property for it with name Router and to give it a function, example:

var express = {
    Router: () => { console.log("Acessou o router"); }
};

In the example above, I could access the property Router easily, as in express.Router().

The problem is that in the above form it would not be possible to invoke the Express object as in express(), since it is an object. If I try to do as in the example below, it gives error:

var express = {
    (): () => { console.log("Iniciou o express"); },
    Router: () => { console.log("Acessou o Router"); }
};

I don’t need to understand specifically how Express does, but I would just like to understand how this would be possible, since in my view it would not be possible for an object to work with direct function calls.

  • Related: https://answall.com/q/474549/112052 (explains that every function is also an object and therefore may have properties)

1 answer

4


In Javascript, every function is an object.

And it’s quite simple, escaping the formality of language, to prove it. See:

function x() {}
x instanceof Object; //-> true

In more detail, "function objects" implement an internal property to which the specification refers as [[Call]]. Every Javascript object that has this internal property is a function and therefore can be invoked.

As functions are objects, it becomes possible to attach any property to a function. Although it is not possible to use literal object notation to define the [[Call]] of a function (as the question suggests), one can create the function and then assign the desired properties.

In the case of Express, it would be something like:

function express() {
  // return new express instance
}

express.Router = function() {
  // return new router instance
};

If several properties are to be added, one can use Object.assign, which facilitates the allocation:

function express() {
  // return new express instance
}

Object.assign(express, {
  Router: function() {
    // return new router instance
  }
});

A little related: Why Arrays and Functions are Objects?.

  • Thank you very much for the explanation. One last question I have, of course, without wanting to abuse the good will, but why do I need to instantiate the express directly for it to work? Maybe the question is stupid, but I could not see sense in the creation of an instance of express, since if I have access to the Router property without instantiating, because I could not have access to the property also Listen without instantiating the express directly. Type, because it works: const router = express.Router(); but not this: const app = express.System("port", ()=>{});

  • I cannot answer this categorically (since it was an API design option from the Express creator), but I think this is useful so that several instances of Express can be created and used at the same time. Having only one instance already provided could be limiting in some scenarios. The object created by Router and the instance of express are different things. Property listen is in the instances created by express(), and not on the object itself (function) express.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.