题目 17 / 31

为什么调用同一个函数的两种方式会打印出不同的值?

知识点: this 绑定难度: 基础

this 完全由调用点的语法形式决定,而不是由函数定义在哪里决定。

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

预测输出结果

预测两行输出。obj.foo() 和 foo2() 调用的是同一个函数对象——为什么结果不一样?

function foo() {
  console.log(this.a);
}
var obj = { a: 1, foo };
var a = 2;
var foo2 = obj.foo;

obj.foo();
foo2();
查看答案与完整解析

正确输出

1
2

为什么会这样

foo 只被声明了一次,随后作为属性挂到了 obj 上。调用 obj.foo() 是一次成员表达式调用,隐式绑定让 this 指向 obj,this.a 读到 1。

foo2 只是一个普通变量,保存着同一个函数对象的引用,调用语法里没有附带任何接收者。

调用 foo2() 是一次无接收者的调用,于是默认绑定生效,this 解析为全局对象,而它的 a 属性早已被 var a = 2 设置为 2,因此结果是 2。

这道题考察什么

  • this 绑定在调用点决定,而不是在函数定义处决定
  • 以 obj.method() 形式调用时,隐式绑定优先生效
  • 把方法拆解到裸变量中会剥离掉隐式绑定

运行环境前提

假设运行在经典的非严格模式脚本中,顶层的 var 声明同时也会成为全局对象的属性,供默认绑定读取。

规范参考

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

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