【问题标题】:Why operator inside parenthesis changes `this` in function call为什么括号内的运算符会在函数调用中更改`this`
【发布时间】:2020-12-23 12:47:42
【问题描述】:

谈话很便宜;给我看代码。

// 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 正在做一些奇怪的事情。我怀疑它在返回值时会进行赋值(因为如果我们进行赋值,也会发生相同的结果),但我不确定。

更新:

&&|| 运算符上也可以看到效果:(0 || obj.fn)()

【问题讨论】:

    标签: javascript this comma-operator


    【解决方案1】:

    给定:

    foo.bar()
    

    bar 内部,this 将是foo

    (也有例外,比如bar定义了箭头函数,但在这种情况下不适用)。

    给定:

    const bar = foo.bar;
    bar();
    

    现在该函数在没有foo 上下文的情况下被调用,所以this 现在是默认对象(在浏览器中为window)。

    表达式:(1, foo.bar) 计算为右侧。这就是函数。

    就像你将它复制到一个变量中一样,这会在你调用它之前断开函数与对象的连接,所以你会得到相同的效果。

    没有赋值,因为您没有涉及变量,但是您调用的是表达式的结果,而不是直接调用对象方法。

    【讨论】:

    • 嗯,很有趣; 这会在你调用它之前将函数与对象断开,所以你会得到相同的效果。但它与(a.fn)();有什么不同
    • 可以将(1, a.fn)(); 视为(function(){ 1; return a.fn;}())(); 对吗?而(a.fn)(); 就变成了a.fn();
    • @Leonardo (a.fn) 没有逗号运算符,只是a.fn,括号不会引起评估
    • @Kaddath 所以没有evaluation 发生在你用括号括起来时,比如(2)?只有comma operator 评估?
    • @Leonardo 括号仅控制执行操作的顺序,如果需要,它不会阻止对事物进行评估,例如在var a = (1 + 1) * 2; 事物被评估。在(1, a.fn)(); 中,括号仅确保在函数调用之前生成逗号运算符。昏迷运算符不是唯一导致评估的东西
    【解决方案2】:

    为了支持@Quentin 的回答,逗号运算符确实将最后一个操作数作为 没有上下文的函数(因此是窗口)返回,而不是对象蓝图中的那个。

    只有在对象上调用apply/call函数时,才能取回上下文。

    (1, a.fn).call(a);  // "inside object"
    (1, a.fn).apply(a); // "inside object"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      • 2018-02-24
      • 1970-01-01
      • 2019-06-05
      相关资源
      最近更新 更多