JS 的 this 是怎么工作的

引言:初期学习 JS 的时候,通常会对以下的问题存在疑惑

1:写 JS 时,this 为啥时而指向 window,时而指向当前对象?

2:箭头函数的 this 为啥 "不听话"?和普通函数到底差在哪?

3:call/apply/bind 改 this 指向,该怎么选才不踩坑?

一、this 是什么

首先,我们要明白一点,this 不是 "指向函数自身"

this 是函数执行时的 "上下文对象"

在实际应用时, this 具体代表的时谁,看的是 this 被谁调用

this 是一个代词,用在不同的地方代表不同的值

1.如果 this 被用在全局,在浏览器环境下,this 指向的其实是 window

js 复制代码
function fn() { console.log(this); }
fn(); // 浏览器环境下 this 指向 window

2.如果 this 在被函数调用时,涉及 this 的绑定规则

二、this的绑定规则

1. 默认绑定

当函数被独立调用时,函数中的 this 指向 window

例如

js 复制代码
function fn() { console.log(this); }
fn(); // 浏览器环境下 this 指向 window

又如

js 复制代码
var a = 1
function foo() {
  console.log(this.a); // 1
}

再如

js 复制代码
var a = 1
function foo() {
  console.log(this.a);
}
function bar () {
  var a = 2
  foo()
}
bar() //  浏览器为 1, node 为 undefined

注意:这里全局作用域下的 var a = 1 ,其实等效于 window.a , 而 Node.js 中模块内 var 声明的变量不挂载到 global

2.隐式绑定

当函数引用有上下文对象且被该对象调用时,函数中的 this 会绑定 到这个上下文对象上

例如

js 复制代码
const foo = {
  a: 1,
  bar: function() {
    console.log(this.a);
  }
}
foo.bar() // 1

只有这种写法,函数作为属性值被调用,才叫被函数调用

3.隐式丢失

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

例如

js 复制代码
function foo() {
  console.log(this.a);
}

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

有点像英语里的就近原则

4. 显示绑定

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

常见的就是这几种,相当于是强行掰弯 this 到别人身上

现在来介绍他们的写法

1.call

js 复制代码
// 带参数的函数
const fn = function(b, c) {
  console.log(this.a + b + c);
};

// 最简调用:this + 零散参数
fn.call({a: 2}, 3, 4); // 输出 9(2+3+4)

2.bind

返回的是一个函数,需要人为调用

js 复制代码
const fn1 = function(b, c) {
  console.log(this.a + b + c);
};

// 写法1:先绑定(this+预设参数),后传剩余参数
const boundFn = fn.bind({a: 2}, 3);
boundFn(4); // 输出 9(2+3+4)

// 写法2:极致简洁(绑定+调用一行完成)
fn1.bind({a: 2}, 3, 4)(); // 输出 9

3.apply

延迟执行,属于异步

apply 只传 "必须的"------ 绑定的 this + 一维数组参数,数组能字面量就不临时变量

js 复制代码
const fn2 = function(b, c) {
  console.log(this.a + b + c);
};

// 场景1:参数是现成数组(最简)
const params = [3, 4];
fn2.apply({a: 2}, params); // 输出 9(2+3+4)

// 场景2:参数是临时数组(字面量写法,一行完成)
fn2.apply({a: 2}, [3, 4]); // 输出 9

汇总而言就是:

  • call:参数逐个传递,调用后立即执行

  • apply:参数以数组传递,调用后立即执行(适配参数不确定场景)

  • bind:参数逐个传递,返回新函数(延迟执行,适配定时器 / 事件)

  • 一句话区分:call/apply 立即执行,bind 延迟执行;call 散传参数,apply 传数组

三、 new 绑定

就像前面文章

[JS 原型与原型链"为什么构造函数 new 出来的实例,都能用同一个方法?" 这背后就是 "原型 + 原型链" 的复用逻 - 掘金](https://juejin.cn/post/7605051978872045587 "https://juejin.cn/post/7605051978872045587")

所介绍的,详细讲述了 new 内部的 this 工作原理,简单来说就是

1.new 的原理会导致函数的 this 指向实例对象

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

四、箭头函数的 this

简单来说,就两句话:

箭头函数中没有 this 这个概念,写在了箭头函数中的 this ,也是它外层那个非箭头函数的 this

箭头函数继承的外层 this 无法修改

相关推荐
程序员大阳2 分钟前
HTML+CSS+JS对话式实战(6)-学生端查看活动功能开发
javascript·css·html·模块·查看学生
jay神23 分钟前
基于 YOLOv8 的轴承缺陷检测(Web 版)
前端·人工智能·yolo
jay神31 分钟前
基于 YOLOv8 的森林火灾检测系统(Web 版)
前端·yolo
code2cat36 分钟前
HTML基础篇之第一张网页:从index.html到浏览器里的任务清单
前端·html
miss1 小时前
AI 改完不敢上线?OpenSpec 规约驱动开发实战
前端·代码规范·前端工程化
AiMan2 小时前
腾讯ima还是不可以导出左侧所有对话,只能单条导出,方法不对吗
前端
去伪存真2 小时前
并发量一高就装死?Agent 全链路“防猝死”手册
前端·agent
Moment2 小时前
AI 编程时代,聊聊我的 Mac mini 双屏桌面
前端·后端
AiMan2 小时前
先确认能不能一次把Microsofat Copilot所有内容打包一个文件导出
前端
总要学点什么2 小时前
第97篇:三维数据加载-城市建筑白模自定义着色器——让一条光带沿高度扫上去,快慢却由帧率说了算
前端·gis·webgl·cesium·着色器·空间分析·白模