admin管理员组

文章数量:1313746

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 :/

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 ma operator and as you can see in the last statement ma 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)()

Share Improve this question edited Jan 2, 2023 at 14:21 Mechanic asked Sep 4, 2020 at 8:51 MechanicMechanic 5,3904 gold badges19 silver badges42 bronze badges 0
Add a ment  | 

2 Answers 2

Reset to default 10

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.

To support @Quentin's answer, the ma 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"

本文标签: javascriptWhy() changes this in function callStack Overflow