Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

call() a function within its own context

var f = function() {
  this.x = 5;
  (function() {
    this.x = 3;
  })();
  console.log(this.x);
};

f.call(f);

f();

f.call();

Running var f as f.call(f) outputs 5. When running it as f() or f.call() outputs 3.

What happens in each case? What does the inner function's this refer to?

like image 734
El Anonimo Avatar asked May 06 '19 15:05

El Anonimo


People also ask

Can you call a function from within itself?

Calling a function from within itself is called recursion and the simple answer is, yes.

Can I call a function inside another function?

To call a function inside another function, define the inner function inside the outer function and invoke it. When using the function keyword, the function gets hoisted to the top of the scope and can be called from anywhere inside of the outer function.

How can you call a function and assign the this context to an object?

Therefore, you can easily write a function hook by using the apply() method. For instance, we want to add a feature to jQuerys . css() method. We can store the original function reference, overwrite the function with custom code and call the stored function.

What is the context of a function?

Context in JavaScript is related to objects. It refers to the object within the function being executed. this refers to the object that the function is executing in.


4 Answers

First Case:

In the first you are calling the function. And inside the function the function itself i.e f is set as this. So in first example this.x = 5; sets the property x on the function.

When the inner function is called this refers to window object so this.x = 3; changes the x property of window object.

When it logs console.log(this.x); here the same property x which was set as property of function is logged.

Second Case:

In the second example this inside the outer function refers to window so when this.x = 3; is evaluated the window.x becomes 3. As this refers to window in outer function so console.log(this.x); logs window.x which is 3

Conclusion:

The conclusion of the whole discussion is that if no argument is passed to call() then automatically window object is binded. According to MDN

thisArg

Optional. The value of this provided for the call to a function. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode, null and undefined will be replaced with the global object and primitive values will be converted to objects.

See the below snippet.

function foo(){
  console.log(this);
}
foo.call(foo); //foo function
foo.call(); //window object
like image 200
Maheer Ali Avatar answered Oct 16 '22 16:10

Maheer Ali


If there is no specific context, this will be window. Your inner function always runs without a context, so it'll set window.x to 3. If you call f(), it will also run with this being window therefore logging the 3.

If you however do f.call(f), this will be the f function object, and it's x property will be set to 5.

  f.call(f)
  console.log(
    f.x, // 5
    window.x // 3
  );

I'd recommend stepping through it with the debugger if it isn't clear yet.

like image 43
Jonas Wilms Avatar answered Oct 16 '22 17:10

Jonas Wilms


When you call f with a reference to itself, it sets the x property to 5 on the function and the inner anonymous function has its this referring to the window, so it sets window.x to 3. Outside the anonymous function, this still refers to the function f, so console.log(this.x) outputs 5.

When you invoke f using f() or f.call() the function f and the anonymous function inside it have a this reference set to the window (the default) and so changing the value of this.x inside or outside the anonymous function affects the output result.

You can see this clearly if you console.log the values of this inside the function f and inside the inner anonymous function.

var f = function() {
	console.log("This inside function f:", this.toString());
  this.x = 5;
  (function() {
	  console.log("This inside anonymous inner function:", this.toString());
    this.x = 3;
  })();
  console.log(this.x);
};
console.log("calling function x with this set to itself");
f.call(f);
console.log("---------------")
console.log("invoking function x with brackets ()")
f();
console.log("---------------")
console.log("calling function x without setting this context")
f.call();
console.log("---------------")
like image 2
Unmitigated Avatar answered Oct 16 '22 18:10

Unmitigated


Further to the other answers, should you want predictable behaviour, you have at least 2 methods available to you.

Method 1: (closure)

var f = function() {
  this.x = 5;
  var that = this;
  (function() {
    that.x = 3;
  })();
  console.log(this.x);
};

f.call(f); // 3

f(); // 3

f.call(); // 3

Method 2: (arrow function)

var f = () => {
  this.x = 5;
  (function() {
    this.x = 3;
  })();
  console.log(this.x);
};

f.call(f); // 3

f(); // 3

f.call(); // 3
like image 1
Adrian Bartholomew Avatar answered Oct 16 '22 17:10

Adrian Bartholomew