教学实验的核心是让新人亲手触发不同调用方式,亲眼看到 this 指向谁、为什么变、在哪断开——不是背规则,而是建立直觉;通过四组对比实验(隐式绑定断开、普通函数与箭头函数嵌套、call(null/undefined)差异)和 console.table 可视化总结,配合防呆练习强化规则内化。

直接用代码跑一遍,比讲十遍规则更管用。教学实验的核心是让新人亲手触发不同调用方式,亲眼看到 this 指向谁、为什么变、在哪断开——不是背规则,而是建立直觉。
用同一函数,换四种调用方式
准备一个极简函数,只做一件事:打印 this 和 this.name:
function showThis() {
console.log('this →', this);
console.log('this.name →', this.name);
}
再准备几个基础环境:
- 全局变量 name = 'global'
- 对象 const obj = { name: 'obj', showThis }
- 构造函数 function Person(n) { this.name = n; }
然后逐个执行,边敲边问:“这次是谁在调用?this 应该是谁?”
重点对比三组易错实验
这三组专门针对新人最常栽跟头的地方,每组都包含“看起来一样,结果却不同”:
① obj.method() vs fn = obj.method; fn()
前者输出 obj.name,后者输出 global(或 undefined,严格模式下)。立刻暴露“隐式绑定靠调用时的点号左边,不是靠函数从哪来”。
② 普通函数内嵌套函数 vs 箭头函数
在 obj.showThis 里写:
function inner() { console.log('inner:', this.name); }
const arrow = () => console.log('arrow:', this.name);
inner(); arrow();
结果:inner 的 this 是 window(默认绑定),arrow 的 this 还是 obj(继承外层)。不用解释“词法绑定”,看结果就懂区别。
③ call(null) vs call(undefined) vs call({})
在非严格模式下,前两者仍指向 window;严格模式下才真正变成 null 或 undefined。这个实验能自然带出“严格模式影响默认绑定”的事实,不靠死记。
用 console.table 做可视化总结
最后把四条规则对应到真实调用示例,用表格现场生成:
console.table([
{ 调用方式: 'showThis()', 绑定规则: '默认绑定', this值: 'window/undefined' },
{ 调用方式: 'obj.showThis()', 绑定规则: '隐式绑定', this值: 'obj' },
{ 调用方式: 'showThis.call(obj)', 绑定规则: '显式绑定', this值: 'obj' },
{ 调用方式: 'new Person("A")', 绑定规则: 'new绑定', this值: '新实例' }
]);
表格一出来,优先级(new > 显式 > 隐式 > 默认)和适用场景一目了然。不需要抽象描述,全是刚亲手运行过的代码。
加一个“防呆”小练习
给一段有 bug 的事件回调代码,比如:
const btn = document.querySelector('button');
const handler = {
name: 'clicker',
onClick() { console.log(this.name); }
};
btn.addEventListener('click', handler.onClick); // 点击时输出 undefined
让新人改——不许用箭头函数,只用已学的四条规则解决。他们会自己试出 bind、call 包一层、或改写成 handler.onClick.bind(handler)。动手修正的过程,就是规则内化的关键一步。











