掌握 JavaScript 的“变色龙”——this 关键字完全指南

"this 到底指向谁?"

几乎每个前端都在控制台里抓狂过。本文带你逐条拆解 this 的四条核心规则、箭头函数特例与常见坑点,附赠记忆口诀与实战 Demo,一次性扫清疑惑。


一、this 是什么?

  • 不是函数本身,不是函数词法作用域
  • 是"调用者"在运行时偷偷塞进来的隐藏参数------谁把我喊出来,我就指向谁
  • 因此 this 与函数声明位置无关,与调用方式有关

二、四条黄金规则(涵盖 99% 场景)

规则 触发场景 this 指向 严格模式差异

  1. 默认绑定 普通函数直接调用 foo() 浏览器:window;Node:global 严格 → undefined
  2. 隐式绑定 对象方法调用 obj.foo() 方法所属对象 丢失场景见下文
  3. 显式绑定 call/apply/bind 手动指定的第一个参数 传 null/undefined 会被忽略 → 回退到全局
  4. new 绑定 new Foo() 新创建的实例 构造器默认 return this

记忆口诀:"无点默认,有点隐式,call 显式,new 实例"


三、规则详解 + 代码示例

① 默认绑定

js 复制代码
function foo() {
  console.log(this.a);
}
var a = 1;
foo(); // 1 (非严格)
js 复制代码
'use strict';
foo(); // undefined → 不再指向 window

② 隐式绑定 & 常见的"丢失"陷阱

js 复制代码
const obj = {
  a: 2,
  foo: foo
};
obj.foo(); // 2 → this === obj

隐式丢失三件套(面试高频):

js 复制代码
// 1. 赋值
const bar = obj.foo;
bar(); // 1 → 回到默认绑定

// 2. 传参
setTimeout(obj.foo, 0); // 1 → 回调里丢失 obj

// 3. 运算符
(false || obj.foo)(); // 1

破解办法:bind / 箭头函数 / 包装函数


③ 显式绑定

js 复制代码
const obj = { a: 3 };
foo.call(obj); // 3
foo.apply(obj, []); // 3

const bar = foo.bind(obj);
bar(); // 永远 3

bind 柯里化:

js 复制代码
function add(a, b) { return a + b + this.c; }
const bound = add.bind({ c: 10 }, 5); // 固定 this 与第一个参数
console.log(bound(2)); // 5+2+10 = 17

④ new 绑定

js 复制代码
function Animal(name) {
  this.name = name;
}
const dog = new Animal('旺财');
console.log(dog.name); // 旺财

构造器显式返回对象会覆盖默认 this:

js 复制代码
function Foo() {
  this.x = 1;
  return { y: 2 }; // 返回新对象 → this 被丢弃
}
console.log(new Foo()); // { y: 2 }

四、箭头函数:this 的"静态快照"

箭头函数没有自己的 this,它捕获外层函数执行上下文的 this(词法作用域)。

js 复制代码
function timer() {
  this.seconds = 0;
  setInterval(() => {
    this.seconds++; // 继承 timer 的 this
  }, 1000);
}
new timer();

对比普通函数:

js 复制代码
setInterval(function () {
  this.seconds++; // 丢失 → window.seconds 或报错
}, 1000);

结论

  • 事件回调 / 定时器想保留外部 this → 箭头函数最简洁
  • 需要动态 this(如 jQuery 插件)→ 不能用箭头函数

五、常见场景速查表

代码片段 this 指向
obj.method() obj
(obj.method)() obj(括号不改变)
(obj.method = obj.method)() 默认绑定
事件侦听器 el.addEventListener('click', handler) el(DOM 元素)
内联事件 <button onclick="handler()"> 全局(非严格)
箭头函数 const f = () => this 外层 this
类方法 class A { m() {} } 实例(需 new A().m()

六、调试技巧

  1. 控制台打印:
js 复制代码
console.log(this);
debugger; // 断点查看调用栈
  1. 显式绑定调试:
js 复制代码
function logThis() {
  console.log(this);
}
logThis.call({ id: 42 }); // 立即确认指向
  1. 开发环境开启严格模式:
js 复制代码
'use strict'; // 让默认绑定变成 undefined,更快暴露错误

七、一句话总结(背下来)

"this 永远指向调用它的对象;没有调用者就回退到全局(或 undefined);箭头函数除外,它只看出生环境。"


八、互动练习

js 复制代码
const obj = {
  fn: function () {
    return this;
  },
  arrow: () => this
};
console.log(obj.fn());   // ?
console.log(obj.arrow()); // ?
const { fn, arrow } = obj;
console.log(fn());        // ?
console.log(arrow());     // ?

答案:

obj → window → undefined → window


把这篇文章收藏起来,下次再遇到 this 疑难杂症,先问"调用点在哪",再看"四条规则",90% 的问题都能秒解。祝你早日驯服这只"变色龙"!

相关推荐
枫,为落叶3 小时前
【vue】设置时间格式
前端·javascript·vue.js
渣哥3 小时前
对象居然不用自己创建?Spring 依赖注入机制的真相惊呆了!
javascript·面试·github
勇敢di牛牛4 小时前
Vue+mockjs+Axios 案例实践
前端·javascript·vue.js
Rhys..5 小时前
JS - npm init
开发语言·javascript·npm
程序0076 小时前
HTML+JS+CSS实现汽车官网
javascript·css·html
没有鸡汤吃不下饭6 小时前
H5移动端页面实现快递单号条形码/二维码扫描,亲测可行!!
前端·javascript·vue.js
云枫晖6 小时前
JS核心知识-模块化
前端·javascript
Asort6 小时前
JavaScript设计模式(十五)——解释器模式 (Interpreter)
前端·javascript·设计模式
喝西瓜汁的兔叽Yan6 小时前
书架效果的实现
javascript·vue.js