找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2133

积分

0

好友

300

主题
发表于 18 小时前 | 查看: 2| 回复: 0

原文地址:https://medium.com/javascript-in-plain-english/5-more-vanilla-javascript-patterns-people-keep-re-inventing-with-libraries-20538bca9d6c

原文作者: Ignatius Sani

我上一篇文章《5 Vanilla JS Patterns That Replace Entire Libraries》显然引起了不少共鸣。这也印证了我一直以来的一个直觉:开发者渴望用更少的代码、更少的依赖,甚至零臃肿,来完成更多事情。

从反馈来看,这一趋势背后还有一个关键驱动力:安全性。每一个引入的第三方依赖,都是一个潜在的安全风险。最小化依赖树不仅关乎性能优化,更关乎构建更具韧性、更易防御的应用程序。

因此,这里带来续篇:再分享5个遵循80/20法则的模式。它们能让你以20%的成本,获得80%的核心功能。你很可能并不需要为这些场景引入专门的库,但也很可能正在不自觉地“重复造轮子”。

1. 一次性事件监听器

你是否曾需要一个只执行一次的事件处理器?像onetime这样的库正是为此而生。但你知道吗?浏览器其实早就提供了一个更简洁、更标准的内置方案。

const button = document.querySelector("#myButton");
button.addEventListener("click", () => {
  console.log("This will only be logged once.");
}, { once: true });

就这么简单。{ once: true }这个选项会告诉浏览器:在第一次触发并执行回调后,自动移除该监听器,无需任何手动清理代码。

模式洞察:在为一个“一次性”需求引入依赖之前,先检查一下原生API。很多时候,原生方案不仅更简单,而且更健壮,能够妥善处理手写实现容易遗漏的边界情况。

2. 可组合的工具函数(告别迷你版Lodash)

你有多少次仅仅是为了链式调用几个操作,就引入了Lodash中的flowpipe函数?其实,使用纯JavaScript写一个小而美的工具函数,就能轻松实现强大的函数组合能力。

// 从右至左执行函数 (类似于 compose)
const compose = (...fns) => (initialValue) =>
  fns.reduceRight((acc, fn) => fn(acc), initialValue);

const double = (x) => x * 2;
const increment = (x) => x + 1;
const stringify = (x) => `Result: ${x}`;

const processNumber = compose(stringify, increment, double);
console.log(processNumber(10)); // "Result: 21"

模式洞察:很多时候,你真正需要的只是“函数组合”这个核心能力本身,而非一个动辄十几KB的工具库。一个亲手编写的辅助函数,就能提供同等效力,且没有任何额外负担。

3. 使用 AbortController 进行异步清理

当用户跳转页面或组件卸载时,你需要取消一个正在进行的fetch请求?在你准备引入第三方库之前,不妨先认识一下AbortController——它是用于取消异步操作的原生标准方案。

const controller = new AbortController();
const { signal } = controller;

fetch("/api/slow-data", { signal })
  .then((res) => res.json())
  .then(console.log)
  .catch((err) => {
    if (err.name === "AbortError") {
      console.log("Fetch aborted successfully.");
    }
  });

// 在需要时调用此方法以取消请求,例如在组件的卸载生命周期中
controller.abort();

模式洞察:市面上有不少用于处理“可取消异步任务”的小型库,但如今,这已经是一个原生、强大且体积极小的Web标准能力了。直接使用它能让你的代码更现代、更标准。

4. 用 MutationObserver 替代 DOM 轮询监视器

需要在DOM结构发生变化时做出响应?虽然有些库提供了封装,但浏览器本身就内置了一个高效的解决方案,远比使用setInterval进行轮询要优雅和精确得多。

const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.type === 'childList') {
      console.log('A child node has been added or removed.');
    }
  });
});

// 开始观察 document.body,监听配置的变动
observer.observe(document.body, {
  childList: true, // 观察直接子节点的变化
  subtree: true,   // 观察所有后代节点的变化
});

// 之后,可以停止观察
// observer.disconnect();

模式洞察:监听DOM变化并不需要引入一个几KB的库,只需要一个MutationObserver实例。只要观察的目标节点(此处为body)或其子树中有节点被添加或移除,回调函数就会触发。你还可以通过mutation.addedNodesmutation.removedNodes来获取具体变化的节点信息。

5. 自定义响应式存储:发布/订阅模式

在大型复杂应用中,一个成熟的状态管理库确实不可或缺。但对于许多小型应用或独立组件而言,你完全可以用观察者模式,仅用几十行代码实现一个简易的响应式存储。

function createStore(initialState) {
  let state = initialState;
  const subscribers = new Set();

  return {
    subscribe(callback) {
      subscribers.add(callback);
      // 返回一个取消订阅的函数,方便使用
      return () => subscribers.delete(callback);
    },
    setState(newState) {
      state = typeof newState === 'function' ? newState(state) : newState;
      subscribers.forEach(callback => callback(state));
    },
    getState() {
      return state;
    }
  };
}

// 使用示例
const store = createStore({ count: 0 });

const unsubscribe = store.subscribe((currentState) => {
  console.log("State changed:", currentState);
});

store.setState({ count: 1 });
// 控制台输出: State changed: { count: 1 }

store.setState((prevState) => ({ count: prevState.count + 1 }));
// 控制台输出: State changed: { count: 2 }

unsubscribe(); // 停止监听状态变化

一点提醒:正如一些敏锐的读者指出的,如果你正在React这类框架中开发,自定义存储可能并非最佳选择。像useReducer和Context API这类框架原生工具,往往更符合其生态的惯用写法,集成度也更高。

这个模式最适合用于与框架无关的纯JavaScript代码、小型Widget,或者作为理解状态管理库底层原理的绝佳练习。

总结

库是工具,而模式是杠杆。

下次当你准备执行npm install之前,不妨先停下来问自己一句:

“我是否能用几行原生JavaScript实现这个核心需求?”

很多时候,答案是肯定的。更重要的是,亲手构建这些模式是一项宝贵的基础能力。它会迫使你去理解功能“是什么”背后的“为什么”,从而让你成长为一位更有深度、更具资源整合能力的开发者。即便在大型项目中最终选择了成熟的库,你也会因为真正理解其底层机制而做出更明智的技术决策。

在探索这些原生模式、精简技术栈的过程中,也欢迎你来云栈社区交流你的实践心得,共同探讨前端开发的更多可能性。




上一篇:Maui Shell:基于Qt的跨终端Linux桌面环境详解
下一篇:Next.js 实战:5周从零上线AI产品的全栈开发与技术栈复盘
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-14 19:14 , Processed in 0.262328 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表