为什么括号会在函数调用中改变 `this`
Why 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 :/
我读过 ydkjs 书,我熟悉调用站点和动态 this
绑定,但我不明白为什么最后一个函数调用 window
作为它的 this
语境;在这个受控实验中,唯一的事情
已更改 ()
和 comma operator
,正如您在最后一条语句中看到的那样,comma operator
正在做一些奇怪的事情。我怀疑它在 returns 值 时进行了赋值(因为如果我们进行赋值,会发生相同的结果) 但我不确定。
更新:
在 &&
、||
运算符上也可以看到效果:(0 || obj.fn)()
给定:
foo.bar()
在 bar
内,this
将是 foo
。
(也有例外,比如bar
定义了一个箭头函数,但不适用这种情况)
给定:
const bar = foo.bar;
bar();
现在函数在没有 foo
上下文的情况下被调用,所以 this
现在是默认对象(在浏览器中是 window
)。
表达式:(1, foo.bar)
计算为 right-hand 侧。这是函数。
就像您将它复制到一个变量一样,这会在您调用它之前断开函数与对象的连接,所以您会得到相同的效果。
没有赋值,因为您没有涉及变量,但您正在调用表达式的结果,而不是直接调用对象方法。
为了支持@Quentin 的回答,逗号运算符确实 returns 作为没有上下文的 函数的最后一个操作数 (因此 window)而不是那个来自对象的蓝图。
只有在带有对象的函数上调用 apply/call 时,它才能获得上下文。
(1, a.fn).call(a); // "inside object"
(1, a.fn).apply(a); // "inside object"
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 :/
我读过 ydkjs 书,我熟悉调用站点和动态 this
绑定,但我不明白为什么最后一个函数调用 window
作为它的 this
语境;在这个受控实验中,唯一的事情
已更改 ()
和 comma operator
,正如您在最后一条语句中看到的那样,comma operator
正在做一些奇怪的事情。我怀疑它在 returns 值 时进行了赋值(因为如果我们进行赋值,会发生相同的结果) 但我不确定。
更新:
在 &&
、||
运算符上也可以看到效果:(0 || obj.fn)()
给定:
foo.bar()
在 bar
内,this
将是 foo
。
(也有例外,比如bar
定义了一个箭头函数,但不适用这种情况)
给定:
const bar = foo.bar;
bar();
现在函数在没有 foo
上下文的情况下被调用,所以 this
现在是默认对象(在浏览器中是 window
)。
表达式:(1, foo.bar)
计算为 right-hand 侧。这是函数。
就像您将它复制到一个变量一样,这会在您调用它之前断开函数与对象的连接,所以您会得到相同的效果。
没有赋值,因为您没有涉及变量,但您正在调用表达式的结果,而不是直接调用对象方法。
为了支持@Quentin 的回答,逗号运算符确实 returns 作为没有上下文的 函数的最后一个操作数 (因此 window)而不是那个来自对象的蓝图。
只有在带有对象的函数上调用 apply/call 时,它才能获得上下文。
(1, a.fn).call(a); // "inside object"
(1, a.fn).apply(a); // "inside object"