Function is an Object?
Tags: javascript, programming
Published: 2022-06-30 16:00:54

### 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](https://tc39.es/ecma262/#sec-ecmascript-language-types)

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

```javascript
function foo() {}
 console.log( typeof foo);		// -> 'function' - WHAT?
```

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](https://tc39.es/ecma262/#sec-typeof-operator). There are the steps of `typeof` function but just focus on step 5th:

```
5. Return a String according to Table 41.
```

![img](https://firebasestorage.googleapis.com/v0/b/meow-dev-380ec.appspot.com/o/upload%2F1656579932832_Screenshot%20from%202022-06-30%2016-05-11.png?alt=media&token=36faaec4-1273-4919-ab4e-d8d276a06e9e)

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 

```javascript
function foo() {
	return 0;
}
```
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_.
3. Let `F` be `OrdinaryFunctionCreate(Function.prototype, Parameters, FunctionBody)`.
4. Perform `SetFunctionName(F, name)`.
5. Perform `MakeConstructor(F)`.
6. 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`.

```javascript
function foo() {}
console.log( foo.name );	// -> "foo"
```

#### 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.

```javascript
"hello"()
//-> Uncaught TypeError: "hello" is not a function
```

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

```javascript
let obj = {};
obj()
//-> Uncaught TypeError: obj is not a function
```

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__.