Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why operator inside parenthesis changes `this` in function call

Talk is cheap; show me the code.

// equals to this.test = "inside window"
var test = "inside window";

function f () {
  console.log(this.test)
};

var obj = {
  test: "inside object",
  fn: f
};

obj.fn();      // "inside object"   --> fine
(obj).fn();    // "inside object"   --> fine
(1, obj).fn(); // "inside object"   --> fine
(obj.fn)();    // "inside object"   --> fine
(0 || obj.fn)(); // "inside window"   --> why?

// reference equality check
console.log(
  f === obj.fn && 
  (obj.fn) === f && 
  f === (1, obj.fn)
); // all equal :/

I had read ydkjs book and Im familiar with call-site and dynamic this binding, but I don't understand why the last function call has window as its this context; in this controlled experiment that only thing that is changed () and comma operator and as you can see in the last statement comma operator is doing something weird. I suspect it does an assignment when it returns the value (since if we do an assignment the same result happens) but I'm not sure.

UPDATE:

The effect is also seen on &&, || operators: (0 || obj.fn)()

like image 432
Mhmdrz_A Avatar asked Sep 04 '20 08:09

Mhmdrz_A


People also ask

What is inside the function parentheses?

In JavaScript, the functions wrapped with parenthesis are called “Immediately Invoked Function Expressions" or "Self Executing Functions. The purpose of wrapping is to namespace and control the visibility of member functions. It wraps code inside a function scope and decrease clashing with other libraries.

Why are parenthesis used to wrap a JavaScript function call?

The parentheses encapsulating the function declaration tell the JavaScript engine to execute the code immediately after it's parsed.

How do you use parentheses in JavaScript?

Parenthesis are used in an arrow function to return an object. Parenthesis are used to group multiline of codes on JavaScript return statement so to prevent semicolon inserted automatically in the wrong place.

What is double parentheses in JS?

It means that the first function ( $filter ) returns another function and then that returned function is called immediately. For Example: function add(x){ return function(y){ return x + y; }; } var addTwo = add(2); addTwo(4) === 6; // true add(3)(4) === 7; // true. Follow this answer to receive notifications.


2 Answers

Given:

foo.bar()

Inside bar, this will be foo.

(There are exceptions, such as when bar is defined with an arrow function, but they don't apply in this case).

Given:

const bar = foo.bar;
bar();

Now the function has been called without the context of foo so this is now the default object (which is window in a browser).

The expression: (1, foo.bar) evaluates as the right-hand side. This is the function.

Just as if you had copied it to a variable, this disconnects the function from the object before you call it, so you get the same effect.

There's no assignment because you haven't involved a variable, but you are calling the result of an expression and not the object method directly.

like image 196
Quentin Avatar answered Oct 19 '22 19:10

Quentin


To support @Quentin's answer, the comma operator indeed returns the last operand as a function without context (hence window) rather than the one from the object's blueprint.

Only on calling apply/call over the function with the object, it can gain the context back.

(1, a.fn).call(a);  // "inside object"
(1, a.fn).apply(a); // "inside object"
like image 21
Abhilash Avatar answered Oct 19 '22 19:10

Abhilash