LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

深入理解 JavaScript 中的 this 与数据存储的奥秘

zhenglin
2026年7月6日 9:46 本文热度 54

深入理解 JavaScript 中的 this 与数据存储的奥秘

从浏览器缓存到函数调用,一次搞懂前端核心概念

作为一名前端开发者,我们每天都要面对两个绕不开的话题:数据存储this 指向。它们看似毫不相关,却在日常开发中频繁交织。今天,就让我们从存储技术切入,再到 JavaScript 中让人头疼的 this,一步步揭开它们的神秘面纱。

一、数据存储的多重宇宙

数据存储从来不是一个单一的概念,它就像一座分层的大厦,每一层都有自己的使命。

1.1 持久化存储:MySQL 与关系型数据库

当我们需要永久保存数据时,MySQL 这类关系型数据库是首选。它以表格形式组织数据,通过 SQL 语言进行增删改查,保证了数据的一致性持久性。用户注册信息、订单记录、文章内容……这些需要长期保存的数据,最终都会落入 MySQL 的“怀抱”。


-- 典型的 MySQL 查询

SELECT * FROM articles WHERE user_id = 123;

但 MySQL 也有它的“软肋”——每次查询都需要磁盘 I/O 和复杂的解析执行,当并发量上来后,性能瓶颈就会出现。

1.2 缓存层:Redis 的 KV 哲学

为了弥补 MySQL 的性能短板,Redis 应运而生。它基于内存运行,采用键值对(Key-Value)存储,读写速度比 MySQL 快数个数量级。


第一次请求:MySQL 查询 → 结果存入 Redis

后续请求:直接走 Redis → 无需再查 MySQL

这种“先读缓存,缓存未命中再查数据库”的模式,是现代高并发系统的标配。Redis 就像 MySQL 的“加速器”,让数据访问变得飞快。

1.3 浏览器缓存与本地存储

当数据来到前端,存储形态又发生了变化:

  • 浏览器缓存(HTTP Cache):让页面二次打开时“秒开”,资源文件(CSS、JS、图片)被缓存下来,无需重新下载。

  • LocalStorage / SessionStorage:以键值对形式存储在浏览器中,容量约 5-10MB,适合存储用户偏好、主题设置等轻量数据。

  • Cookie:容量小(约 4KB),但会自动携带在请求头中,常用于身份认证。

1.4 前沿阵地:LLM 与 Embedding 存储

在 AI 时代,存储的边界被进一步拓展。大语言模型(LLM)使用 Embedding 向量来存储文本的语义信息,通过向量数据库(如 Pinecone、Milvus)进行相似度检索。这是一种全新的存储范式——数据智能

存储技术的发展,从 MySQL 到 Redis,从 LocalStorage 到向量数据库,本质是在速度、容量、持久性、智能性之间寻找平衡。


二、前端表单:从默认提交到 Ajax 进化

让我们回到前端开发的日常场景——表单。

index.html 中,我们有一个经典的 form 结构:

<form class="add-items">

  <input type="text" name="item" placeholder="Add a new tapas">

  <input type="submit" value="+ Add Item">

</form>

当用户点击 type="submit" 的按钮时,表单会触发 submit 事件,浏览器会执行默认行为:向 action 属性指定的地址发送请求,并刷新页面。

这种做法在传统 Web 应用中很常见,但在现代前端开发中,我们更倾向于用 JavaScript 接管提交逻辑,以提供更流畅的用户体验。


const oForm = document.querySelector('.add-items');


function addItem(e) {

  console.log(e);

  console.log(this);

  // 阻止提交默认行为 —— 不刷新页面

  e.preventDefault();

  // 这里可以写 fetch / ajax 逻辑

}


// 监听 submit 事件

oForm.addEventListener('submit', addItem);

通过 e.preventDefault() 阻止默认的页面刷新,然后用 fetchXMLHttpRequest 异步提交数据,这就是 Ajax 的核心思想。页面不再刷新,用户感知到的只有数据的局部更新,体验大大提升。


三、this:函数运行时的“灵魂”

如果说 JavaScript 中哪个概念最让人困惑,this 一定名列前茅。很多人把 this 理解为“函数声明时”确定的,这是错误的。正确的理解是:

this 在函数运行时确定,指向函数的调用者。

我们来看一段代码(来自 2.html):

var name = "用户A";

let obj = {

  name: "用户B",

  say: function() {

    console.log(this.name);

  }

}

obj.say(); // 输出:用户B

这里 say 作为对象 obj 的方法被调用,this 指向 obj,所以输出 "用户B"

但如果把函数引用赋值给一个变量再调用呢?

const fn = obj.say;

fn(); // 输出:用户A(在非严格模式下)

这时 fn 作为普通函数被调用,this 指向全局对象 window,所以输出 "用户A"。但如果在 common.js 中我们开启了严格模式:

"use strict";

// 严格模式下,普通函数的 this 为 undefined

这就是 严格模式 的意义之一:减少隐式的全局污染。

3.1 this 的五种场景

场景this 指向
普通函数调用(非严格模式)window / global
普通函数调用(严格模式)undefined
对象方法调用调用该方法的对象
构造函数调用(new)新创建的实例对象
事件处理函数触发事件的 DOM 元素

3.2 事件处理函数中的 this

common.js 中,我们给链接绑定了点击事件:

document.querySelector('.lnk')

  .addEventListener('click', goBaidu);


function goBaidu(e) {

  console.log(this); // 指向 <a class="lnk" href="..."> 元素

  e.preventDefault();

}

作为事件处理函数,this 默认指向触发事件的 DOM 元素,这与普通函数的调用方式不同。


四、手动指定 this:call / apply / bind

很多时候,我们并不想让 this 由调用方式决定,而是手动控制。JavaScript 提供了三个方法:callapplybind

4.1 call:立即调用,逐个传参

let obj = {

  name: "用户C",

  speak: function(a, b) {

    console.log(a, b);

    console.log(this.name);

  }

}


let obj2 = { name: "用户D" };


// 使用 call,将 this 指向 obj2

obj.speak.call(obj2, '你好', '我是用户D');

// 输出:你好 我是用户D  用户D

call 的第一个参数是想要绑定的 this 对象,后面的参数依次传递给函数。

4.2 apply:立即调用,数组传参

applycall 几乎相同,区别在于传递参数的方式:

obj.speak.apply(obj2, ['你好', '我是用户D']);

// 效果与 call 相同,但参数以数组形式传递

当参数数量不确定或来自数组时,apply 会更加方便。

4.3 bind:延迟调用,返回新函数

bind 与前两者最大的区别是:它不立即执行函数,而是返回一个绑定好 this 的新函数

const fn2 = obj.speak.bind(obj2);

console.log(fn2); // 返回一个新函数

fn2('你好', '我是用户D'); // 此时 this 已经绑定为 obj2

这在异步场景中非常有用,比如 setTimeout 或事件监听:

// common.js 中的示例

const addItemBind = addItem.bind(obj);

oForm.addEventListener('submit', addItemBind);

这里用 bindaddItem 函数的 this 永久绑定为 obj,这样在事件触发时,this 就不会指向表单元素,而是指向我们指定的对象。

4.4 异步场景中的 this 陷阱

2.html 中,有一段被注释掉的代码:

setTimeout((function() {

  console.log(this.name)

}).bind(this), 1000);

为什么要用 bind(this)?因为在 setTimeout 中,回调函数是作为普通函数被调用的,this 会指向 window(非严格模式)。为了让 this 保持在当前上下文中,我们需要手动绑定。

而箭头函数则天然解决了这个问题:

setTimeout(() => {

  console.log(this.name)

}, 1000);


五、箭头函数:没有 this 的“另类”

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

var name = "用户A";

let obj = {

  name: "用户B",

  say: function() {

    setTimeout(() => {

      console.log(this.name); // 继承 say 函数的 this → obj

    }, 1000);

  }

}

obj.say(); // 1秒后输出:用户B

say 方法中,箭头函数的 this 沿用了外层 say 函数的 this(即 obj),所以输出 "用户B"

如果用普通函数:

setTimeout(function() {

  console.log(this.name); // 普通函数,this 指向 window

}, 1000);

// 输出:用户A(非严格模式)


这就是箭头函数在异步回调中广受欢迎的原因——它帮我们绕过了 this 的动态绑定问题

但要注意,箭头函数不能作为构造函数(不能使用 new),也不能使用 callapplybind 改变其 this(因为根本没有自己的 this)。


六、综合思考:从表单提交到 this 绑定

让我们把这些知识串联起来,看一个完整的场景:

common.js 中,我们使用 bindaddItemthis 绑定为 obj

const oForm = document.querySelector('.add-items');

let obj = {

  name: "用户C",

  // ...

}


const addItemBind = addItem.bind(obj);

oForm.addEventListener('submit', addItemBind);

为什么要这样做?因为事件监听函数默认的 this 指向 DOM 元素(oForm),但我们希望在 addItem 函数中能访问到 obj 的数据或方法。通过 bind,我们既保留了事件对象 e,又让 this 指向了我们想要的对象。

如果使用 callapply,它们会立即执行函数,而 addEventListener 需要的是一个函数引用(在事件触发时被调用),所以 bind 是最合适的选择。



七、总结

概念核心要点
数据存储MySQL(持久化)→ Redis(缓存加速)→ LocalStorage(浏览器存储)→ Embedding(AI 存储),各有适用场景
表单提交默认提交会刷新页面,用 e.preventDefault() + Ajax 实现无刷新提交
this 指向函数运行时确定,取决于调用方式(普通调用、方法调用、构造函数、事件处理)
call / apply立即执行,手动指定 this,区别在于传参方式(逐个 vs 数组)
bind返回新函数,延迟执行,适合事件监听和异步回调
箭头函数没有自己的 this,继承外层作用域,简化代码但使用场景受限

最后思考:理解 this 的关键,不是背诵规则,而是理解“函数被调用时,谁在调用它”。而理解存储的关键,是明白“数据在何时、以何种方式被访问”。这两者看似不同,但都指向同一个核心——对上下文(Context)的深刻理解



该文章在 2026/7/6 9:46:42 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-1  粤公网安备44030602007207号