javascriptthiscomma-operator

Why`()` 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)()


Solution

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