在前端开发中,this 是高频考点也是极易踩坑的核心知识点,它的核心规则:this 的指向由函数调用方式决定,而非函数声明位置 。结合本地存储项目实战代码,本文拆解 this 5 种调用场景、call/apply/bind 手动绑定、箭头函数特殊规则,搭配完整可运行案例代码。
一、前置知识:项目文件结构
本次实战配套一套完整前端页面,包含 4 个核心文件,所有示例代码均可直接运行:
index.html:页面骨架,表单、链接 DOM 元素common.js:this 基础调用、call/apply/bind 完整示例- 2.html:箭头函数 + setTimeout 经典 this 陷阱案例
- 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 声明变量会挂载到 window,let/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 指向,核心区别:
call(obj, 参数1, 参数2):立即执行函数,参数逐个传递apply(obj, [参数1, 参数2]):立即执行函数,参数放入数组传递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 核心,同时前端存储也是面试高频知识点,各类存储适用场景区分:
- MySQL:后端关系型数据库,持久化存储核心业务数据
- Redis:内存 KV 缓存,减轻数据库压力,热点数据缓存
- 浏览器本地存储 localStorage/sessionStorage:前端页面持久化简单数据,本项目演示本地存储清单
- 文件存储:本地 json、csv、excel 等离线文件
- 云盘:云端大容量文件存储
- LLM 向量存储:大模型 Embedding 向量数据,智能检索场景
前端表单默认提交会刷新页面,开发中均使用fetch/Ajax异步提交,结合 localStorage 做前端数据持久化,搭配本文的 this 知识处理表单事件逻辑。
四、核心知识点总结
- this 动态绑定规则:调用方式决定指向,声明位置不影响;
- 普通函数:全局 window(严格模式 undefined);对象方法:调用对象;事件函数:DOM 元素;构造函数:实例;
- call/apply 立即执行改 this,bind 返回新函数延迟使用;
- 箭头函数无自身 this,捕获外层作用域 this,不支持手动绑定;
- var 污染全局 window,let/const 不会挂载全局变量,开发优先使用 let/const。
整套代码可直接复制运行,覆盖浏览器 DOM、定时器、对象方法、事件绑定全部业务场景,吃透即可解决 90% 前端 this 相关面试与开发问题。