DEV Community

Ashutosh Sarangi
Ashutosh Sarangi

Posted on • Edited on

Deep understanding of Functions in javascript

  1. Functions are First class Objects why?

Ans:-
a. we can treat functions like other variables in JavaScript. how this is possible
b. When the compiler sees a function declaration/expression
it keeps the function in the memory along with an attachment of Object reference.
and return the function store reference to the variable.

c. so basically functions are function + Object combo.

  1. What is function declaration vs function expression?

Ans:-

function declaration


function functionDeclaration () {
console.log('This is function declaration);
}
Enter fullscreen mode Exit fullscreen mode

Function Expression

a. Named Function Expression
b. Anonymous Function Expression

IIFE:- Immediate invoke Function Expression 3 types of function expression


const item = function namedFunctionExpression () {}


const anonymousFunctionExpression= function () {}
//Here anonymousFunctionExpression is storing/Refering an anonymous function 

Arrow function

Const temp = () => {}
Enter fullscreen mode Exit fullscreen mode

Very Important:- (Clear Ideas on When to use Arrow fun and call , apply and bind also this reference.)

const user1 = {
scope: 1,
increment : () => {
  this.scope++; // Here this would be window Object
}

increament1: function () {
  console.log(this); // here this is who called this function
}

increment2: function () {
     function nested() {
       console.log(this); // Here this will check for who called it as it has nothing so this will be window. to resolve this problem we need call / APPly / Bind this to this function see increment3 func
     }
     nested();

}

increment3: function () {
   function nested() {
      console.log(this); // now it will have the this which was bind  with call
   }
   nested.call(this);
}

increment4: function () {
  const nested = () => {
     console.log(this); // here we will get this as who called this.
  }
  nested(); // because in arrow function ewe don't have this so it picks from lexical scope. So here we don't need external bindings 

}

function add() {

}

user1.increment();

Enter fullscreen mode Exit fullscreen mode
  1. When we call user1.increment() here user1 is this (keyword).
  2. when we directly call add1() by default windowObject = this (keyword)unless it uses the arrow function.
  3. Inside arrow function it took this reference from lexical scope.

Arrow function is the newer Form of call, apply and bind methods.

Rule :-
methods inside functions should not be arrow functions. If we do so

Function hierarchy

named function Declaration > named Function Expression > Anonymous Function Expression

SO Important note (rule to be followed)

in side Objects functions function should be arrow function not the Objects function named function expression anonymous function expression Arrow function, normal function how does this change in both function types parameter , argument

this keyword depends on how the function is being called

there are 4 ways a function is being called.

  1. implicit binding **obj.fun(); here **this is obj

*Explicitly Binding this *

  1. .call()/.apply() /.bind() (hard bound). -> return a function

  2. with new keyword

  3. default binding (Normal fun call)
    this as global/window in strict mode by default this is undefined

very important note

use strict mode global this would be undefined.

 "use strict"
function fun() {
    console.log(this); // undefined
}

fun()
Enter fullscreen mode Exit fullscreen mode

Arrow function does not have this keyword, so it lexically check the parent.

As per this behaviour it is called Lexical this .

let obj = {
teacher: 'asd',
ask: () => {
console.log(this)
}
}

obj.ask(); 
Enter fullscreen mode Exit fullscreen mode

Here this will be refere to window OBject

Why?

Think lexically it will not be found inside the ask function and then it will go to its parent scope and the parent scope is window.

It is not the Obj Object.

new of the Arrow function fails because it does not have the prototype property.

because of that it throughs error

const fun1 = () => {
    console.log(this);
}

let ob = new fun1(); // Type Error, fun1 is not a constructor
Enter fullscreen mode Exit fullscreen mode

Top comments (6)

Collapse
 
jonrandy profile image
Jon Randy 🎖️
const anonymousFunctionExpression= function () {}
//Here anonymousFunctionExpression is storing/Refering an anonymous function 
Enter fullscreen mode Exit fullscreen mode

This actually isn't correct. The act of assigning an anonymous function to variable in this way makes the function cease to be anonymous. After the assignment, you can check the name property of the function... it will no longer be empty - it will be the name of the variable to which the function is assigned, and therefore no longer anonymous.

Collapse
 
ashutoshsarangi profile image
Ashutosh Sarangi • Edited

Hello Jon,
When 1st compiler sees the function it stores it in memory as an anonymous function and then in the anonymousFunctionExpression variable we will get the reference where it is stored in the memory.

So in other words, what would be the label, where it stored in memory i.e anonymous

Example:-


const arr = [1,2,3];

const newArr = arr; // here it will store the reference of arr, rather than storeing actual reference.

//Similarly, my above analogy relates to **anonymousFunctionExpression**

Enter fullscreen mode Exit fullscreen mode

Hope, I have clarified my viewpoint on the same.

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

But the function object actually being stored in memory is changed by the assignment, JS will set the name property of the function - making it cease to be anonymous as it now has a name. Yes, it is the same function, but it has changed.

// testing the 'name' of an anonymous function
console.log( (function() { return 0 }).name )  // <empty string> - as expected

// testing the name of an 'anonymous' function that was stored in a variable
const test = function() { return 0 })
console.log(test.name)  // 'test' - has a name, no longer anonymous
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
ashutoshsarangi profile image
Ashutosh Sarangi

Yes, you are correct, it will print the function name. but.

As per your analogy

let me give a simple example

const arr = [1,2,3];

const arr2 = arr;

arr2.push(5);
/*because it stores the reference of arr, in arr2 it also updates the arr. along with arr2

same way the function reference is being stored in temp not the actual function, and you can access the properties of the function. as they are having first class Objects. (function + Object combo).
*/

Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
jonrandy profile image
Jon Randy 🎖️ • Edited

Your response is not relevant.

anonymousFunctionExpression is not storing an anonymous function. The function's name property has been changed by the assignment. JS was not always like this, assignments didn't use to touch the name of the function... but this behaviour was changed - mainly I believe to improve stack traces (more names are visible instead of so many anonymous functions).

If you assign a named function to a variable, the name property of the function does not get changed:

const test = function myFunc() { return 0 }
console.log(test.name)  // 'myFunc'
Enter fullscreen mode Exit fullscreen mode

It's actually quite difficult (but not impossible) to keep a reference to an anonymous function somewhere and have it retain its anonymity (not be auto-assigned a name). The only way I know of to do this is to push the anonymous function to an array:

const arr = []
arr.push( function () {} )
console.log(arr[0].name)  // <empty string>
Enter fullscreen mode Exit fullscreen mode

I actually wrote a post about the quirks of function anonymity in JS:

Thread Thread
 
ashutoshsarangi profile image
Ashutosh Sarangi

Hello Jon,

I did not exactly get what point you were trying to express.

But as per my analogy, it is working the same under the hood as I explain.

There is a pointer you explain as when we push the anonymous function into the array

const arr = []
arr.push( function () {} )
console.log(arr[0].name) 

/* 
1. Here also the javascript compiler compilers the function
2. Store it in a memory location and push the reference in an array
3. so when you are trying to get the name of anonymous it will return you <Empty Sting>
*/
Enter fullscreen mode Exit fullscreen mode

const obj = {
    thisShouldbeMyFunctionname: function () {}
};

console.log(obj.thisShouldbeMyFunctionname.name) // thisShouldbeMyFunctionname

/*
thisShouldbeMyFunctionname: function () {}
in this line, we are setting another label (thisShouldbeMyFunctionname) to our anonymous function.

same as in my simple Example
*/

Enter fullscreen mode Exit fullscreen mode

I would admire it, it is a healthy discussion.