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 无法修改

相关推荐
arvin_xiaoting4 小时前
OpenClaw学习总结_I_核心架构_8:SessionPruning详解
前端·chrome·学习·系统架构·ai agent·openclaw·sessionpruning
工程师老罗5 小时前
Image(图像)的用法
java·前端·javascript
早點睡3905 小时前
ReactNative项目OpenHarmony三方库集成实战:react-native-swiper
javascript·react native·react.js
jump_jump6 小时前
深入 JavaScript Iterator Helpers:从 API 到引擎实现
javascript·性能优化
swipe6 小时前
把 JavaScript 原型讲透:从 `[[Prototype]]`、`prototype` 到 `constructor` 的完整心智模型
前端·javascript·面试
问道飞鱼6 小时前
【前端知识】React 组件生命周期:从底层原理到实践场景
前端·react.js·前端框架·生命周期
Dxy12393102166 小时前
JS发送请求的方法详解
开发语言·javascript·ecmascript
CHU7290356 小时前
定制专属美丽时刻:美容预约商城小程序的贴心设计
前端·小程序
浩~~7 小时前
反射型XSS注入
前端·xss
AwesomeDevin7 小时前
AI时代,我们的任务不应沉溺于与 AI 聊天,🤔 从“对话式编程”迈向“数字软件工厂”
前端·后端·架构