DEV Community

Cover image for Function is an Object?
Quy Luong
Quy Luong

Posted on

Function is an Object?

Function is an Object?

If you regularly read articles about Javascript, you will probably see people often say: "Oh function is actually an object". But wait, If it is like that then:

  • Why typeof of function is return "function" instead of "object"?
  • How we can make a function call on an object?

In this article, we're going to "investigate" whether that's the case and clear up misunderstandings about functions.

1. Does typeof return the data type?

Firstly, we need to know about list of data type in Javascript:

  • undefined
  • null
  • boolean
  • string
  • symbol
  • number
  • bigint
  • Object

Learn more at: ECMAScript Specification

As you see, there is no one called 'function'. But let's run this code below:

function foo() {}
 console.log( typeof foo);      // -> 'function' - WHAT?
Enter fullscreen mode Exit fullscreen mode

So are we wrong or does typeof really have a "problem" 🤔?

The typeof Operator

To understand how this function works, we need to search the ECMAScript specification document at Section 13.5.3. There are the steps of typeof function but just focus on step 5th:

5. Return a String according to Table 41.
Enter fullscreen mode Exit fullscreen mode

img

Looking at the last row, if an Object already has a Call method implemented then return "function". Instead of returning the left column (Type of val), typeof returns a string value in the right column. So we can say, typeof does not implicitly return the type.

At this point, we have a clue that the function is actually an object. But this Object is so strange 😬

2. Function object

Then what is Call method?. According ECMAScript specification, function object contains two internal methods: Call and Construct. The Call method must be implemented. Note that internal methods are only called in the Javascript engine, they are not a method of an object. In particular we cannot view them via ".", for example foo.construct.

  • Call: Executes code associated with this object. Invoked via a function call expression.
  • Construct: Creates an object. Invoked via the new operator or a super call.

So to summarize, we can say: an object is considered a function object only if it implements the Call method. Every object that supports Construct must support Call.

3. Function Definitions

So how does Javascript create a function object when we declare it?

Function Declaration

function foo() {
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

The above is a common way of declaring a function. Now let's see how the Javascript engine works.

Firstly, we divide the above statement into small parts according to the following pattern:

function Name ( Parameters ) { FunctionBody }

There are steps that Javascript Engine process:

(I have omitted the steps that are not in the scope of the article)

  1. Let name be string value of Name.
  2. Let F be OrdinaryFunctionCreate(Function.prototype, Parameters, FunctionBody).
  3. Perform SetFunctionName(F, name).
  4. Perform MakeConstructor(F).
  5. Return F.

It has three functions we need to consider OrdinaryFunctionCreate,SetFunctionName,MakeConstructor and at the end it returns an function object F.

Note: Those functions are internal abstract function, Javascript need to implement them in its engine. We can't call them in our code as well.

OrdinaryFunctionCreate Function

It is used to specify the runtime creation of a new function with a default Call internal method and no Construct internal method. It returns a function object.

There are steps:

(I have omitted the steps that are not in the scope of the article)

  1. Let F be OrdinaryObjectCreate(Function.prototype)
  2. Set F.[[Call]] implement.
  3. Return F

We found a new function OrdinaryObjectCreate, It is used to specify the runtime creation of new ordinary objects, it also set Function.prototype into F. And you see, in step 2, Javascript Engine already implement the Call method.

At this point, we know how Javascript assigns the Call method.

SetFunctionName Function

It adds a "name" property to F.

function foo() {}
console.log( foo.name );    // -> "foo"
Enter fullscreen mode Exit fullscreen mode

MakeConstructor Function

It creates a constructor. Invoked via the new operator or a super call. But a function object is not necessarily a constructor and such non-constructor function objects do not have a Construct internal method.

4. Function Call

Function call is one of Left-Hand-Side Expressions. Javascript engine will invoke EvaluateCall function (It is internal function) with the foo function as a parameter func. EvaluateCall run following this steps:

  1. If Type(func) is not Object, throw a TypeError exception.
  2. If IsCallable(func) is false, throw a TypeError exception.
  3. Return ? Call(func).

At step 1, if statement will check type of func is object or not.

"hello"()
//-> Uncaught TypeError: "hello" is not a function
Enter fullscreen mode Exit fullscreen mode

At step 2, IsCallable (internal function) will check Call already implemented or not.

let obj = {};
obj()
//-> Uncaught TypeError: obj is not a function
Enter fullscreen mode Exit fullscreen mode

Finally, the Call() function will be called, which will call the Call method inside the function as we mentioned in OrdinaryFunctionCreate Function.

At this point, we can understand that even though a function is an object, but an object cannot be called as a function.

Top comments (2)

Collapse
 
armousness profile image
Sean Williams

If you don't know, the main reason to have functions be objects is to support this business:

function make_adder(a) {
    return function(b) {
        return a + b;
    }
}
Enter fullscreen mode Exit fullscreen mode

Once you support lexical closure—allowing inner functions to capture variables from an outer scope—functions have to be objects, because the captured variables have to be stored somewhere.

Collapse
 
lnquy065 profile image
Quy Luong

Wow great, I don't know this one. Thanks for your sharing