干净的代码:JavaScript 不变性、核心概念和工具

干净的代码:javascript 不变性、核心概念和工具

什么是数据可变性?

直接修改现有数据值的行为称为可变性。在 JavaScript 中,对象和数组默认是可变的:

// 可变性示例const user = { name: 'alice' };user.name = 'bob';           // 修改对象属性const numbers = [1, 2, 3];numbers.push(4);             // 修改数组numbers[0] = 0;              // 修改数组元素

这种可变性可能导致难以察觉的错误,尤其是在大型应用中。

为何要避免可变性?

立即学习“Java免费学习笔记(深入)”;

来看一个简单的例子:

// 使用可变性的代码const cart = {  items: [],  total: 0};function addProduct(cart, product) {  cart.items.push(product);  cart.total += product.price;}// 使用示例const myCart = cart;addProduct(myCart, { id: 1, name: "laptop", price: 999 });// myCart 直接被修改console.log(cart === myCart); // true,两个变量指向同一个对象

可变性带来的问题:

共享引用: 代码的不同部分可能在不知情的情况下修改同一个对象。副作用: 修改可能影响到使用同一个对象的其它函数。难以调试: 难以追踪代码的哪一部分修改了对象。复杂测试: 可变性使单元测试更难编写。

解决方案:不可变编程

不可变方法为每次修改都创建数据的新副本:

// 不可变代码function addProduct(cart, product) {  // 创建新对象,不修改原对象  return {    items: [...cart.items, product],    total: cart.total + product.price  };}// 使用示例const initialCart = { items: [], total: 0 };const newCart = addProduct(initialCart, { id: 1, name: "laptop", price: 999 });console.log(initialCart); // { items: [], total: 0 }console.log(newCart);     // { items: [{...}], total: 999 }console.log(initialCart === newCart); // false,它们是不同的对象

这种方法的优势:

可预测性: 每个函数都返回一个新状态,没有隐藏的副作用。更改追踪: 每次修改都会创建一个可追踪的新对象。轻松测试: 函数是纯函数,测试更简单。更好的调试: 可以比较修改前后的状态。

现代不可变性工具

Immer:简洁的编写风格

Immer 允许您编写看起来像普通 JavaScript 代码,但会产生不可变结果的代码:

import produce from 'immer';const initialCart = {  items: [],  total: 0,  customer: {    name: 'alice',    preferences: {      notifications: true    }  }};// 不使用 Immer(冗长方式)const updatedCart = {  ...initialCart,  items: [...initialCart.items, { id: 1, name: "laptop", price: 999 }],  total: initialCart.total + 999,  customer: {    ...initialCart.customer,    preferences: {      ...initialCart.customer.preferences,      notifications: false    }  }};// 使用 Immer(简洁方式)const updatedCartImmer = produce(initialCart, draft => {  draft.items.push({ id: 1, name: "laptop", price: 999 });  draft.total += 999;  draft.customer.preferences.notifications = false;});

Immer 的优势:

熟悉的语法:像平时一样编写代码。无需学习新的 API:使用常规 JavaScript 对象和数组。快速:只复制修改的部分。自动变更检测:只在需要时追踪变更并创建新引用。与 TypeScript 配合良好:保留所有类型信息。

Immutable.js:高效的数据结构

Immutable.js 提供了专门用于不可变性的数据结构:

import { Map, List } from 'immutable';// 创建不可变结构const cartState = Map({  items: List([]),  total: 0});// 添加一个商品const newCart = cartState  .updateIn(    ['items'],    items => items.push(Map({      id: 1,      name: "laptop",      price: 999    }))  )  .update('total', total => total + 999);// Immutable.js 方法总是返回新的实例console.log(cartState.getIn(['items']).size); // 0console.log(newCart.getIn(['items']).size);   // 1// 轻松比较console.log(cartState.equals(newCart)); // false// 转换回普通的 JavaScript 对象const cartJS = newCart.toJS();

Immutable.js 的优势:

快速的不可变数据结构。用于处理数据的丰富 API。节省内存的数据共享。使用 equals() 轻松进行相等性检查。防止意外修改。

用于实现不可变性的 ESLint 配置

ESLint 可以通过特定的规则来帮助执行不可变的编码实践:

// .eslintrc.jsmodule.exports = {  plugins: ['functional'],  rules: {    'functional/immutable-data': 'error',    'functional/no-let': 'error',    'functional/prefer-readonly-type': 'error'  }};

这些规则将:

防止直接数据变异。鼓励使用 const 而不是 let。建议在 TypeScript 中使用只读类型。

TypeScript 和不可变性

TypeScript 通过其类型系统来帮助强制执行不可变性:

// 商品和购物车的不可变类型type Product = {  readonly id: number;  readonly name: string;  readonly price: number;};type Cart = {  readonly items: ReadonlyArray;  readonly total: number;};// TypeScript 防止修改const cart: Cart = {  items: [],  total: 0};// 编译错误:items 是只读的cart.items.push({ id: 1, name: "Laptop", price: 999 });// 函数必须创建一个新的购物车function addProduct(cart: Cart, product: Product): Cart {  return {    items: [...cart.items, product],    total: cart.total + product.price  };}// TypeScript 保证原对象不会被更改const newCart = addProduct(cart, { id: 1, name: "Laptop", price: 999 });

TypeScript 的只读修饰符:

readonly:防止属性更改。ReadonlyArray:防止数组更改。Readonly:使所有属性都只读。

这些类型会在编译时进行检查,有助于尽早发现错误。

结论

不可变性使您的代码更可预测且更易于维护。虽然需要一些时间来适应,但可靠性和可维护性方面的好处是值得的。

以上就是干净的代码:JavaScript 不变性、核心概念和工具的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1500799.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Vuejs 还是 Nuxtjs?
上一篇 2025年12月19日 22:51:44
动画与新标志解锁!!!!
下一篇 2025年12月19日 22:51:55

相关推荐

  • c++中的SFINAE技术是什么_c++模板编程中的SFINAE原理与应用

    SFINAE 是“替换失败不是错误”的原则,指模板实例化时若参数替换导致错误,只要存在其他合法候选,编译器不报错而是继续重载决议。它用于条件启用模板、类型检测等场景,如通过 decltype 或 enable_if 控制函数重载,实现类型特征判断。尽管 C++20 引入 Concepts 简化了部分…

    2026年5月10日
    000
  • 松下案例入选《2025企业社会责任竞争力指数报告》

    松下案例入选《2025企业社会责任竞争力指数报告》松下案例入选《2025企业社会责任竞争力指数报告》松下案例入选《2025企业社会责任竞争力指数报告》松下案例入选《2025企业社会责任竞争力指数报告》

    11月14日,中国新闻社《中国新闻周刊》在北京成功举办了第二十一届企业社会责任系列活动·2025责任之星特别节目。活动以“致明天:焕新责任竞争力”为主题,汇聚了来自政府、企业及学术界的多位代表,共同探讨新时代下企业如何通过责任创新打造核心竞争力。松下电器(中国)有限公司总裁赵炳弟作为企业界代表受邀出…

    2026年5月10日 用户投稿
    000
  • Go语言接口与切片:如何识别和操作[]interface{}

    本文将深入探讨Go语言中如何识别和操作`[]interface{}`类型的切片。我们将介绍类型断言(Type Assertion)的关键作用,并通过`switch`语句演示如何安全地检测`[]interface{}`类型,并进而遍历其内部元素。文章旨在提供清晰的示例代码和专业指导,帮助开发者有效地处…

    2026年5月10日
    300
  • html标签如何读_HTML标签(语义化/结构)阅读与理解方法

    答案是掌握HTML标签的语义化含义与结构作用。理解HTML需从语义化入手,使用如article、nav、header等标签准确表达内容意义,提升可访问性、SEO和代码可维护性;阅读时应从外到内分析结构,识别页面骨架,区分语义标签与非语义标签(如div、span)的合理使用场景,避免仅凭外观选择标签,…

    2026年5月10日
    000
  • 我有时使用 awk 而不是 Python 的四个原因

    Python 是一门强大的编程语言,但在某些特定场景下,Awk 的优势更为显著,尤其体现在可移植性、生命周期、代码简洁性和与其他工具的互操作性方面。 Python 脚本通常具有良好的可移植性,但并非总能在所有环境中完美运行,例如流行的 Docker 基础镜像 (如 Debian 和 Alpine)。…

    2026年5月10日
    000
  • C++如何编译和链接_C++从源码到可执行文件的过程解析

    c++kquote>预处理展开宏和头文件,编译生成汇编代码,汇编转为机器码,链接合并目标文件与库生成可执行程序。 当你写完一段C++代码,比如一个简单的hello world程序,最终能运行起来,背后其实经历了一系列步骤:预处理、编译、汇编和链接。这个过程将人类可读的源码转换成机器可以执行的程…

    2026年5月10日
    000
  • JS注解怎么和TypeScript结合_ JS注解在TypeScript环境下的应用

    TypeScript 支持通过配置 allowJs 和 checkJs 在 JavaScript 文件中识别 JSDoc 注解并进行类型检查,可在混合项目中提升类型安全;常见用法包括 @type、@param、@returns 和 @typedef,能为变量、函数参数等提供类型信息,支持与 .ts …

    2026年5月10日
    000
  • 李彦宏:2025年是萝卜快跑的扩张之年 将寻找合作方

    百度计划2025年大力扩张自动驾驶出行服务平台“萝卜快跑”。百度ceo李彦宏近日在业绩会上宣布,将与电信运营商、出租车公司及其他车队运营商合作,扩大市场份额,让更多用户体验自动驾驶技术。 这对于萝卜快跑而言是至关重要的发展阶段,预计未来车队规模和服务量将实现飞速增长。 ☞☞☞AI 智能聊天, 问答助…

    2026年5月10日
    000
  • 为什么专注如此重要?

    在快节奏的数字时代,程序员能否保持专注直接影响着代码质量、项目进度和错误率。 高效专注,才能在开发过程中游刃有余。本文将分享一些实用技巧,助您提升编程专注力,高效完成任务。 专注力为何如此重要? 专注力是程序员的核心竞争力。编码需要高度集中,处理细节、逻辑和问题,稍一分神就可能导致错误百出,返工耗时…

    2026年5月10日
    300
  • TypeScript函数体中如何高效判断参数类型?

    typescript 函数体中判断参数类型的技巧 typescript 中,我们可以定义接口来表示不同的数据类型。在本文中,我们将探讨如何在函数体中判断参数的类型,从而实现类型收窄,进行更精细的类型检查。 使用谓词函数 一种方法是编写谓词函数来手动检查类型。谓词函数返回的是 value is som…

    2026年5月10日
    000
  • JS如何实现策略模式

    策略模式通过封装算法使其可互换,JavaScript中利用函数作为一等公民实现,适用于表单验证等场景,结合工厂模式提升灵活性,但应避免过度设计。 策略模式的核心在于定义一系列算法,并将每一个算法封装起来,使它们可以相互替换。这使得算法可以在不影响客户端的情况下发生变化。在JS中,这可以通过函数作为一…

    2026年5月10日
    000
  • Svelte中正确导入数据与组件:避免常见误区

    在svelte开发中,理解如何正确导入数据和组件至关重要。svelte文件定义的是组件而非普通javascript模块,若需共享纯数据,应使用`.js`文件进行导出。本文将详细阐述svelte的导入机制,并通过示例代码展示如何区分导入数据与渲染组件,从而避免常见的导入错误,确保项目结构清晰且功能正确…

    2026年5月10日
    300
  • 使用 React 和 Pushpad 进行 Web 推送通知

    本教程演示如何在React网站上轻松实现用户订阅网页推送通知功能。我们将创建一个React组件,方便用户订阅/取消订阅推送通知。 我们将使用Pushpad SDK来创建和管理推送订阅。 一、配置Pushpad JavaScript SDK 首先,在网站根目录添加名为service-worker.js…

    2026年5月10日
    300
  • 如何通过GitHub API高效获取超过100个用户列表(分页教程)

    本教程旨在解决使用GitHub API获取用户列表时遇到的默认100个用户限制问题。我们将详细介绍两种主要的分页策略:利用Octokit库内置的paginate方法实现自动化分页,以及手动实现基于since参数的循环分页逻辑。文章将提供清晰的代码示例,并强调在不同场景下选择合适方法的注意事项,特别是…

    2026年5月10日
    100
  • Go语言中实现多条件排序:使用自定义类型扩展sort.Interface

    在Go语言中,`sort.Sort`函数依赖于`sort.Interface`接口来实现排序。当需要对同一数据集合根据不同字段(如按姓名、按薪资)进行排序时,不能通过在`Less`方法中简单地使用多个`return`语句或尝试对数据结构的不同字段直接调用`sort.Sort`。正确的做法是定义新的类…

    2026年5月10日
    000
  • 前端构建优化:利用常量折叠提升应用性能

    本文深入探讨了一种在构建阶段执行部分源代码以进行优化的技术——常量折叠(Constant Folding)。通过在编译时预计算表达式并替换为最终结果,该技术显著减少了运行时开销,提升了应用性能。文章将详细解释其工作原理、优势,并探讨其在现代前端构建工具中的应用与配置,旨在帮助开发者实现更高效的代码优…

    2026年5月10日
    000
  • 动态语言中静态类型的讽刺

    c++kquote>您也可以在 medium 上阅读这篇文章。 当我们看到编程语言如何随着时间的推移而演变时,总是很有趣。 曾几何时,当我开始进入软件开发世界时,python、php 和 javascript 等动态语言因其灵活性和适合快速开发的简洁语法而受到赞赏。 然而,随着这些弱类型语言的…

    2026年5月10日
    000
  • 它的未来:自动化和人工智能如何改变发展

    自动化与人工智能:IT领域的未来发展 自动化和人工智能(AI)正在深刻地改变着软件开发和IT专业人员的工作方式。从自动化重复性任务到将AI工具融入开发流程,这些技术为IT行业带来了新的机遇和挑战。 1. DevOps中的自动化:简化开发流程 自动化正在彻底改变开发人员管理开发和部署流程的方式。持续集…

    2026年5月10日
    000
  • 为什么 TypeScript 比 JavaScript 更好

    javascript 长期以来一直是 web 开发的基石,支持从小型脚本到大型应用程序的各种项目。然而,随着项目规模的扩大,javascript 的动态类型和缺乏结构性可能会成为开发的瓶颈。typescript 应运而生,它凭借静态类型检查和强大的工具集,迅速成为许多开发者构建可靠、可扩展应用程序的…

    2026年5月10日
    300
  • 深入解析Angular中循环计算与数组操作的常见陷阱及优化实践

    本文深入探讨了angular应用中处理循环计算和动态数组时常见的逻辑错误。通过一个租金计算器示例,我们分析了`for`循环中未能正确累加迭代值以及数组填充不当的问题,并提供了详细的解决方案,包括优化计算逻辑、正确使用数组`push`方法,以及遵循typescript和javascript的最佳实践,…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信