题目 27 / 31

给成员表达式加上括号会改变 this 吗?

知识点: this 绑定难度: 进阶

给属性引用加上括号并不会剥离它——效果和直接调用属性完全一样。

使用执行可视化器解题在下方逐步观察每个绑定、函数调用和控制台输出。

预测输出结果

预测这四行输出。foo、bar 最终都指向和 person.greeting 相同的函数,但分别以四种不同方式调用。

var name = "Window";

var person = {
  name: "Person",
  greeting: function () {
    console.log(this.name);
  }
};

function greeting() {
  var foo = person.greeting;
  foo();

  person.greeting();

  (person.greeting)();

  (bar = person.greeting)();
}

greeting();
查看答案与完整解析

正确输出

Window
Person
Person
Window

为什么会这样

foo() 是通过一个普通变量调用的——这个变量本身并不是属性引用,因此走默认绑定,this 指向全局对象(window),输出 "Window"。

person.greeting() 是一次真正的成员表达式调用:从这个引用上读到的接收者是 person,因此走隐式绑定,this.name 读到 "Person"。

(person.greeting)() 只是给同一个成员表达式加了一对括号。分组运算符只影响求值顺序/优先级,并不会像赋值或逗号表达式那样把属性引用变成一个普通值——调用点没有变化,this 仍然是 person,因此再次输出 "Person"。

(bar = person.greeting)() 看起来很像,但外层表达式其实是一次赋值,而不是一个裸的属性引用。赋值表达式求值为它右侧的值——也就是这个函数本身,接收者信息已经被剥离——因此这次调用的调用点和 foo() 完全一样:走默认绑定,this 又是 window,输出 "Window"。

这道题考察什么

  • this 绑定取决于调用点的引用形式,而不是哪个变量恰好持有这个函数
  • 分组运算符 (...) 永远不会剥离属性引用——只有会产生新值的运算符(赋值、逗号等)才会
  • 把方法复制到一个普通变量里(var foo = obj.method)总会丢失它的接收者

运行环境前提

假设是经典的非严格模式脚本,此时一次没有接收者的调用其 this 默认是全局对象。

规范参考

JavaScript 代码编辑器支持直接编辑或粘贴自定义代码
第 0 步 / 共 0 步
单步Space播放
按 → 单步 或 Space 自动播放
阶段 1: 编译预解析(变量提升与内存分配)
阶段 2: 代码执行(逐行赋值与调用求值)
单步执行原理解析

按键盘右方向键 “→” 进行单步调试,或按空格键 “Space” / 点击 “▶ 自动播放” 进行连续执行。