彻底掌握 JavaScript 中的 this:从懵逼到通透

99 阅读4分钟

前言:为什么 this 是 JavaScript 的"灵魂之问"?

在 JavaScript 的学习之路上,this 几乎是一个无法绕开的"灵魂拷问"。无数开发者曾在它面前困惑不解,又曾在理解它之后豁然开朗。有人说,真正理解 this 是 JavaScript 进阶的重要里程碑。

你是否也曾遇到过这样的场景:

  • 明明在对象中定义的方法,调用时却找不到 this.name
  • 在回调函数中,this 神秘地"消失"了?
  • 看着箭头函数和普通函数中不同的 this 表现,感到一头雾水?

这些问题看似简单,却直指 JavaScript 的核心机制。this 的设计体现了 JavaScript 的灵活性和动态性,但也正是这种灵活性,让初学者感到困惑。

本文将带你深入 this 的世界,从它的存在意义到实际应用,从基础规则到高级技巧,系统地剖析这个 JavaScript 中最重要的概念之一。无论你是正在学习前端的新手,还是希望深入理解 JavaScript 原理的开发者,相信这篇文章都能为你带来新的收获。 前言:为什么 this 是 JavaScript 的"灵魂之问"? 在 JavaScript 的学习之路上,this 几乎是一个无法绕开的"灵魂拷问"。无数开发者曾在它面前困惑不解,又曾在理解它之后豁

为什么要有 this?

在 JavaScript 的世界里,this 就像是一个隐形的"传话筒",this 提供了一个更优雅的方式隐式地传递一个对象引用,可以让代码更简洁易于复用

function identify(context) {
  return context.name.toUpperCase()
}
function speek(context) {
  var greeting = 'hello, I am ' + identify(context)
  console.log(greeting);
}
var me = {
  name: 'Tom'
}
speek(me)//不用this并且逻辑复杂情况下context写的到处都是,容易造成参数传导出现错误

下面是改使用this,原由先不做解释,但这两段代码运行结果是一样的

function identify() {
  return this.name.toUpperCase()
}
function speek() {
  var greeting = 'Hello, I am ' + identify.call(this)
  console.log(greeting);
}
var me = {
  name: 'Tom'
}
speek.call(me)

接着往下看,带你慢慢理解

this 用在哪?

this是一个代词,用在不同的地方代指不同的值。它主要出现在以下两种作用域中:

  1. 全局作用域:在全局作用域中,this指向全局对象(在浏览器中是window,在Node.js中是global)。this===window
console.log(this) //在node上会输出一个{},即代表wiondow的全局
  1. 函数作用域:在函数内部,this的指向取决于函数被调用的方式。

this 的绑定规则

默认绑定

当函数被独立调用时,this 默认指向全局对象:

这是独立调用

var a=1
function foo(){
    console.log(this.a);   
}
foo()//结果为 1

这还是独立调用

var a = 1
function foo() {
  console.log(this.a);
}
function bar () {
  var a = 2
  foo()  //虽然在函数里面,但仍然是独立调用
}
bar()

隐式绑定

当函数被某个对象"拥有"并调用时(即非独立调用时或者说被引用且被调用时),this 绑定到该对象:

function foo() {
  console.log(this);
}

var a = 1
var obj = {
  foo: foo
}
obj.foo()

运行结果

屏幕截图 2025-12-02 174227.png

此时你可能会有一个问题:如果在上面那段代码外层再包装一个函数那该怎么判断?那就得提到下一个点了---隐式丢失,看下面

隐式丢失

当一个函数被多层对象调用时,函数的 this 指向最近的那个对象

function foo() {
  console.log(this.a);
}

var obj = {
  a: 1,
  foo: foo  //引用
}
var obj2 = {
  a: 2,
  foo: obj //引用
}
obj2.foo.foo()

此时foothis指向的是离他最近的obj

显式绑定

显示绑定就是人为的将this绑定到指定的函数上, 使用 callapplybind 可以显式地指定 this

fn.call(obj, x, x) 显示的将fn里面的 this 绑定到obj这个对象上,call 负责帮 fn 接受参数

var obj = {
  a: 1
}                        //在v8眼中人为打造的function都是通过new Function得到的
function foo(x, y) {    // new Function()  // foo.__proto__  === Function.prototype
  console.log(this.a, x + y);
}
foo.call(obj, 1, 2) //将foo中的this指向obj

fn.apply(obj,[x, x]) 显示的将fn里面的 this 绑定到obj这个对象上,call 负责帮 fn 接受参数

var obj = {
  a: 1
}
function foo(x, y) {
  console.log(this.a, x + y);
}
var arr = [1, 2]
foo.apply(obj, arr)

new 绑定

使用 new 关键字调用构造函数时,this 会绑定到新创建的对象:

构造函数中 return 的特殊情况

当构造函数中存在 return ,并且 return 的是一个引用类型的数据,则 new 的返回失效

function Person() {
  this.name = '冯总'
  return {a: 1}
}
let p = new Person()
console.log(p);

image.png

箭头函数中的 this

箭头函数是 ES6 的语法糖,它没有自己的 this,而是继承外层作用域的 this

function foo(){
     var bar = () => {
       console.log(this.a)
  }
}

这里this指向的是foo而非bar

this 绑定优先级总结

  1. new 绑定 - 最高优先级
  2. 显式绑定(call、apply、bind)
  3. 隐式绑定(对象方法调用)
  4. 默认绑定(独立函数调用)