导读:本期聚焦于小伙伴创作的《JavaScript中的this关键字指向什么?一文彻底搞懂调用规则》,敬请观看详情。为什么同一函数在不同地方调用,this的取值天差地别?this的本质是函数执行时的上下文绑定,由调用位置而非定义位置决定。在默认非严格模式下,独立函数调用this指向全局对象,而严格模式则为undefined。方法调用时this归属调用者,构造函数中this指向新实例。箭头函数没有自身this,继承外层词法作用域。通过call、apply、bind可显式改写指向。理清这些规则,才能避开回调中this丢失的坑。

在JavaScript里,this是一个在函数执行阶段才确定的上下文引用,它并不取决于函数写在哪儿,而取决于函数被谁以什么形式调用。很多运行时错误都源于对this绑定时机的误判,比如把方法当回调传出去后内部取不到预期对象。理解this,核心就是看清调用栈顶端的调用关系。

JavaScript中的this关键字指向什么?一文彻底搞懂调用规则

一、默认绑定与严格模式差异

当函数被直接调用,没有任何调用者对象前缀时,就会发生默认绑定。在非严格模式下,浏览器环境里this会指向全局对象window,Node环境指向global。这种绑定最容易被忽略,也是污染全局变量的常见原因。

一旦代码运行在严格模式(即在函数或文件头声明了use strict),独立调用的函数内部this会变成undefined,而不是全局对象。这能帮我们更早暴露错误,避免无意中修改全局状态。下面两段代码对比了两种模式下的表现。

// 非严格模式
function showThis() {
  console.log(this); // 浏览器中输出 window
}
showThis();

// 严格模式
'use strict';
function showStrictThis() {
  console.log(this); // 输出 undefined
}
showStrictThis();

二、隐式绑定与方法调用

如果函数作为某个对象的属性被调用,即“对象.方法()”形式,this就会隐式绑定到该对象。此时函数内部的this引用的是调用时刻点号左侧的那个容器。这种规则非常直观,但要注意“丢失隐式绑定”的情况。

当我们把对象的方法赋值给一个变量,或者作为回调传给另一个函数,再执行时就已经脱离了原对象,变成默认绑定。下面示例展示了方法被抽取后this指向的变化,以及用闭包保留上下文的一种朴素做法。

const user = {
  name: 'Tom',
  greet: function() {
    console.log('你好,我是' + this.name);
  }
};
user.greet(); // 输出:你好,我是Tom

const looseGreet = user.greet;
looseGreet(); // 非严格下 this 为 window,name 为空

// 用闭包固定上下文
const boundGreet = function() {
  const self = user;
  console.log('你好,我是' + self.name);
};
boundGreet();

三、显式绑定 call、apply 与 bind

JavaScript提供了三个原型方法让我们手动指定this:call和apply立刻执行函数并绑定this,差别只在参数传递方式;bind则返回绑定了this的新函数,不立即执行。它们都属于显式绑定,优先级高于隐式绑定。

在实际开发中,借用数组方法处理类数组对象、React类组件绑定事件处理函数,都会频繁用到它们。下面的代码演示了如何用call让伪数组使用数组的slice,以及用bind提前绑定回调函数中的this。

function sum(a, b) {
  console.log(this.prefix + (a + b));
}
const obj = { prefix: '结果:' };
sum.call(obj, 2, 3); // 输出:结果:5
sum.apply(obj, [2, 3]); // 输出:结果:5

const boundSum = sum.bind(obj);
boundSum(4, 5); // 输出:结果:9

四、new绑定与构造函数

当函数通过new关键字调用时,JavaScript会创建一个空对象,将this绑定到该对象,并执行函数体,若未返回其他对象则返回这个this。这就是new绑定,优先级在四种规则中最高。它模拟了传统面向对象语言的实例化过程。

需要注意的是,箭头函数不能作为构造函数使用,因为其没有自己的this,new操作符无法为其绑定实例。下面的例子展示了一个普通构造函数内部this的变化,以及返回自定义对象时会覆盖默认this实例的行为。

function Person(name) {
  this.name = name;
}
const p = new Person('Lucy');
console.log(p.name); // 输出 Lucy

function Special() {
  this.val = 1;
  return { val: 2 }; // 返回对象覆盖this
}
const s = new Special();
console.log(s.val); // 输出 2

五、箭头函数与词法this

箭头函数是ES6引入的特殊函数,它没有自己的this绑定,而是沿用词法作用域中的this,也就是定义时外层函数的this。因此箭头函数内部的this在书写那一刻就定死了,不受调用方式影响,也不会被call改变。

这个特性让箭头函数特别适合用作定时器回调或事件处理器,避免反复bind。但也要小心:如果在顶层定义箭头函数,它的this会直接继承全局或模块作用域。下面展示用箭头函数解决setTimeout中this丢失的经典问题。

const counter = {
  count: 0,
  start: function() {
    setInterval(() => {
      this.count++;
      console.log(this.count);
    }, 1000);
  }
};
counter.start(); // 每秒输出递增数字

六、优先级与综合判断

遇到复杂调用时,可按优先级顺序判断this:new绑定大于显式绑定,显式绑定大于隐式绑定,隐式绑定大于默认绑定。如果同时出现多种迹象,就以最高优先级为准。箭头函数则直接无视这套规则,看外层。

掌握这些后,建议读代码时先找函数执行的那一行,看它左边有没有点、前面有没有new、有没有被call类方法包过,再决定this是谁。多写几个小例子在控制台打印,比死记理论更有效。

调用类型this指向示例
默认调用全局对象或undefinedfn()
隐式调用调用者对象obj.fn()
显式调用指定对象fn.call(obj)
new调用新实例new fn()
箭头函数外层this() => {}

JavaScriptthiscall_stack修改时间:2026-08-09 22:06:42

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。