loading...

A fun conversation to understand (arrowFunction).prototype

oathkeeper profile image Divyesh Parmar ・3 min read

I'm writing this post to document a conversation I had with /u/senocular on reddit. I was asking about if it is disadvantageous to that arrow functions lexically bind "this"?

Later on I got intrigued to know that arrow Function's doesn't have their constructor like how normal functions have in their prototype property.

It sounds like you're trying to ask about one thing, but really could be two...? First:

...if the arrow functions have their own constructor function...

This is a good question. And the answer is no. While arrow functions are functions (obviously), and inherit from the Function type, they do not have their own constructor - at least not one specific to arrow functions. Of the available function constructors, you have:

  • Function

  • GeneratorFunction

  • AsyncFunction

  • AsyncGeneratorFunction

Function is actually the only one thats globally accessible, the others are only accessible through instances of functions of their respective function types as created with the function keyword.

console.log(Function) // Function () {}
console.log(GeneratorFunction) // Error, not defined
console.log(AsyncFunction) // Error, not defined
console.log(AsyncGeneratorFunction) // Error, not defined

but

console.log(function * () {}).constructor) // GeneratorFunction () {}
console.log(async function () {}).constructor) // AsyncFunction () {}
console.log(async function * () {}).constructor) // AsyncGeneratorFunction () {}

Arrow functions, on the other hand, are just considered normal functions despite their unique behavior and syntax.

console.log((() => {}).constructor) // Function () {}

Variations of arrow functions also correlate to their respective function type

console.log((async () => {}).constructor) // AsyncFunction () {}

Note: arrow functions aren't supported for generators though there is a proposal for this in stage 1.

But if you use a function constructor to create a function, it will have normal function behavior, not arrow function behavior.

(() => this).call('value') // global (undefined in strict)
new Function('return this').call('value') // 'value'

You can consider this a limitation of the Function constructor. It simply doesn't support the creation of arrow functions much in the same way it doesn't support being able to create closures.

{
  let outer = 'value'
  new Function('return outer')() // Error, outer not defined
}

Now, all this could be unrelated to

...like how normal fucntions have in their prototypes?

This depends on what you mean by prototypes. Do you mean the prototype of the functions or do you mean the prototype property of the functions?

As objects, functions have prototypes which point to their respective types - what they inherit from, or more specifically the prototype property of their types. For example a normal function instance inherits from Function.prototype. This is where it gets methods like call and apply. We've also seen from above that other function variations have their own function types like GeneratorFunction and AsyncFunction which also have their own prototype properties those functions inherit from.

console.log(Object.getPrototypeOf(function * () {}) === GeneratorFunction.prototype) // true

In this sense, arrow functions also have prototypes which refer to their respective function types.

console.log(Object.getPrototypeOf(() => {}) === Function.prototype) // true

As you can see, this is still Function and not anything unique like ArrowFunction because arrow functions don't have their own specific constructor type.

On the other hand, arrow functions themselves do not have their own prototype property, meaning they can't be used as constructors or represent a type themselves.

const arrowFn = () => {}
console.log(arrowFn.prototype) // undefined
new arrowFn() // Error, not a constructor

In fact most function variations coming out of ES6+ don't have their own prototype properties and cannot be constructors.

const obj = { method () {} }
console.log(obj.method.prototype) // undefined
new obj.method() // Error, not a constructor

const asyncFn = async function () {}
console.log(asyncFn.prototype) // undefined
new asyncFn() // Error, not a constructor

Exceptions are class functions, as they are explicitly meant to represent constructors (but as with object methods above, class methods cannot be constructors), and generator functions which are a result of a bug in the spec that allowed them to be constructors in ES6. This bug was fixed in ES7 and while generators can no longer be constructors, their prototype property was still left behind

const genFn = function * () {}
console.log(genFn.prototype) // Object {}
new genFn() // Error, not a constructor

When it comes down to it, arrow functions are just variations of normal functions. They have the same constructors, but those constructors can't create them, and arrow functions themselves also can't be constructors.

Posted on by:

oathkeeper profile

Divyesh Parmar

@oathkeeper

Game Of Thrones is real PERIOD Learning #Node.js, #express.js #JavaScript, #Python, #Reactjs #Redux

Discussion

pic
Editor guide