JavaScript this 指向全解实战指南

在前端开发中,this 是高频考点也是极易踩坑的核心知识点,它的核心规则:this 的指向由函数调用方式决定,而非函数声明位置 。结合本地存储项目实战代码,本文拆解 this 5 种调用场景、call/apply/bind 手动绑定、箭头函数特殊规则,搭配完整可运行案例代码。

一、前置知识:项目文件结构

本次实战配套一套完整前端页面,包含 4 个核心文件,所有示例代码均可直接运行:

  1. index.html:页面骨架,表单、链接 DOM 元素
  2. common.js:this 基础调用、call/apply/bind 完整示例
  3. 2.html:箭头函数 + setTimeout 经典 this 陷阱案例
  4. readme.md:理论知识点汇总

index.html 页面代码(DOM 环境基础)

html

预览

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>LocalStorage</title>
</head>
<body>
  <div class="wrapper">
    <h2>LOCAL TAPAS</h2>
    <ul class="plates">
      <li>Loading Tapas...</li>
    </ul>
    <!-- 表单用于测试事件处理函数this -->
    <form class="add-items" >
      <input type="text" name="item" placeholder="Add a new tapas" required>
      <input type="submit" value="+ Add Item">
    </form>
    <!-- a标签测试点击事件this -->
    <a href="https://www.baidu.com" class="lnk">去百度</a>
  </div>
<script src="./common.js"></script>
</body>
</html>

页面提供表单、超链接 DOM,用来演示事件处理函数中 this 的指向

二、this 五大调用场景实战解析

场景 1:普通函数直接调用 → this 指向全局 window

全局使用 var 声明变量会挂载到 windowlet/const 不会污染全局;开启严格模式后普通函数 this 为undefined

js

运行

javascript 复制代码
// common.js
"use strict";
var name = "佳明"; // var挂载window
let obj = {
  name: "赖庆庆",
  say: function() {
    console.log(this.name)
  }
}
// 将对象方法赋值给变量,单独调用变为普通函数
const fn = obj.say;
fn(); // 普通函数调用,严格模式下this为undefined,报错读取name

场景 2:作为对象方法调用 → this 指向调用该方法的对象

方法通过对象.方法()执行时,this 绑定调用者:

js

运行

scss 复制代码
obj.say(); // 输出:赖庆庆,this === obj

场景 3:DOM 事件处理函数 → this 指向触发事件的 DOM 元素

原生事件监听中,函数内部 this 默认绑定触发元素,示例:

js

运行

javascript 复制代码
// 点击a标签时,this指向<a class="lnk">元素
document.querySelector('.lnk').addEventListener('click', goBaidu);
function goBaidu(e) {
  console.log(this); // <a href="https://www.baidu.com" class="lnk">去百度</a>
  e.preventDefault(); // 阻止跳转默认行为
}

场景 4:手动绑定 this:call /apply/bind

三者均可修改函数 this 指向,核心区别:

  1. call(obj, 参数1, 参数2):立即执行函数,参数逐个传递
  2. apply(obj, [参数1, 参数2]):立即执行函数,参数放入数组传递
  3. bind(obj):返回全新函数,不会立即执行,适合异步 / 事件绑定

完整示例:

js

运行

arduino 复制代码
let obj2 = {
  name: "甜总"
}
obj.say.call(obj2); // 输出:甜总
obj.say.apply(obj2); // 输出:甜总

function speak(a,b) {
  console.log(this.name, a, b)
}
speak.call(obj2,'你好','我是甜总'); // 甜总 你好 我是甜总
speak.apply(obj2,['你好','我是甜总']); // 甜总 你好 我是甜总

// bind返回新函数,延迟执行
const fn2 = obj.speak.bind(obj2);
fn2('你好','我是甜总');

实战场景:表单事件绑定自定义 this

表单 submit 事件默认 this 是 form 元素,用 bind 永久绑定自定义对象:

js

运行

ini 复制代码
const oForm = document.querySelector('.add-items');
function addItem(e) {
  e.preventDefault();
  console.log(this.name); // 绑定后this指向obj
}
const addItemBind = addItem.bind(obj);
oForm.addEventListener('submit', addItemBind);

场景 5:箭头函数无独立 this,继承父级作用域 this

箭头函数不存在自己的 this,不会绑定 call/apply/bind,内部 this 定义时上层普通函数的 this,经典定时器案例见 2.html:

html

预览

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
<script>
var name = "梅西";
let obj = {
  name: "姆巴佩",
  say: function() {
    // 普通函数,this指向obj
    console.log(this.name); // 姆巴佩
    // 箭头函数继承外层say函数的this(obj)
    setTimeout(() => {
      console.log(this.name) // 姆巴佩
    }, 1000)
  }
}
obj.say();
</script>
</body>
</html>

如果把定时器换成普通 function,内部 this 会指向 window,无法读取姆巴佩,这是开发中最常见的 this 陷阱,箭头函数完美解决。

三、拓展:前端存储体系补充

理解 this 是前端 JS 核心,同时前端存储也是面试高频知识点,各类存储适用场景区分:

  1. MySQL:后端关系型数据库,持久化存储核心业务数据
  2. Redis:内存 KV 缓存,减轻数据库压力,热点数据缓存
  3. 浏览器本地存储 localStorage/sessionStorage:前端页面持久化简单数据,本项目演示本地存储清单
  4. 文件存储:本地 json、csv、excel 等离线文件
  5. 云盘:云端大容量文件存储
  6. LLM 向量存储:大模型 Embedding 向量数据,智能检索场景

前端表单默认提交会刷新页面,开发中均使用fetch/Ajax异步提交,结合 localStorage 做前端数据持久化,搭配本文的 this 知识处理表单事件逻辑。

四、核心知识点总结

  1. this 动态绑定规则:调用方式决定指向,声明位置不影响;
  2. 普通函数:全局 window(严格模式 undefined);对象方法:调用对象;事件函数:DOM 元素;构造函数:实例;
  3. call/apply 立即执行改 this,bind 返回新函数延迟使用;
  4. 箭头函数无自身 this,捕获外层作用域 this,不支持手动绑定;
  5. var 污染全局 window,let/const 不会挂载全局变量,开发优先使用 let/const。

整套代码可直接复制运行,覆盖浏览器 DOM、定时器、对象方法、事件绑定全部业务场景,吃透即可解决 90% 前端 this 相关面试与开发问题。

相关推荐
何出无名之师1 小时前
AIDL的一次调用链路追踪之二,如何和驱动打交道
前端
weedsfly1 小时前
JS垃圾回收:从原理到项目实战,彻底根治内存泄漏
前端·javascript·面试
Jcc1 小时前
虚拟 DOM 是什么?从 Snabbdom 理解 Vue 的 DOM 更新机制
前端
user62229864925811 小时前
Vue 常用技术知识全景:从响应式到组件通信的系统理解
前端
feiyu_gao1 小时前
一个人 + AI:246 commits 做出设计系统 CLI 的故事
前端·ai编程·交互设计
奶油mm1 小时前
从 0 到 1 搭建高可用 Redis Cluster:踩坑、优化与生产实践
前端
掘金安东尼2 小时前
Agent Loop 深度调研:把决定权交给模型的一次换代,为什么发生在现在
前端
亿元程序员2 小时前
Cocos视频拼图,终于支持微信小游戏了!
前端