js为啥设计成单线程的。 异步的产生又是什么原因?
JavaScript被设计成单线程的,主要基于以下几个原因:
- 简单性: 单线程模型简化了语言的并发模型,因为程序员不需要担心多线程带来的复杂性,如线程同步、死锁和竞态条件等问题。这使得语言更易于学习和使用。
- 安全性: 在Web浏览器环境中,JavaScript主要用于与用户交互、操作DOM(文档对象模型)和处理事件。如果JavaScript允许多线程执行,那么多个线程可能同时修改DOM或其他共享资源,导致不可预测的行为和竞态条件。单线程模型避免了这种同步问题,确保了代码的可靠性和安全性。
- 历史背景: JavaScript最初被设计为一种简单的脚本语言,用于增强网页的动态功能。由于当时浏览器的限制和设计目标,单线程模型被认为是最合适的选择。
然而,单线程模型也有其缺点,最显著的是它不能充分利用现代多核处理器的并行计算能力,而且长运行时间的任务会阻塞UI响应,影响用户体验。为了解决这些问题,JavaScript引入了异步编程模型。
异步产生的原因:
- 非阻塞性: 异步编程允许长时间运行的操作(如网络请求、文件读写等)在不阻塞主线程的情况下执行。这样,即使某个操作需要较长时间才能完成,其他代码仍能在主线程上继续执行,保持应用程序的响应性。
- 事件驱动: 异步编程通常基于事件循环机制。当异步操作完成时,它们会通过回调函数、Promise或async/await语法将结果返回给主线程,这样就可以在适当的时候处理结果,而不会阻塞其他任务。
- 资源管理: 异步编程帮助有效地管理有限的系统资源,如网络连接和文件句柄,因为它们在完成操作后会释放资源供其他操作使用。
总之,JavaScript的单线程特性和异步编程模型是为了解决特定的工程和设计问题,它们共同保证了语言的简单性、安全性和响应性,同时也提供了处理高负载和复杂操作的能力。
可以用useMemo代替useCallback吗
在大多数情况下,你应该使用 useCallback 来缓存函数,而不是 useMemo。然而,在某些特殊情况下,例如当函数体内的计算非常昂贵,且你想要缓存函数的计算结果而非函数本身时,你可以使用 useMemo 来返回一个函数,该函数内部再使用 useMemo 来缓存计算结果。
有了解过抓包吗 为什么https还会被抓包
抓包(Packet Sniffing)是指在网络中捕获和分析数据包的过程,主要用于网络故障排查、性能监控、安全审计以及开发调试等场景。抓包工具能够截获网络接口上流经的数据包,并对这些数据包进行解析,展示出它们的详细内容。
那么,为什么抓包工具还能看到HTTPS的明文数据呢?这通常涉及以下几种情况:
- 中间人攻击(MITM) : 抓包工具如Charles、Fiddler或Burp Suite可以通过充当客户端和服务器之间的代理,执行SSL中间人攻击。这意味着抓包工具会终止HTTPS连接,创建两个单独的HTTPS连接(一个从客户端到抓包工具,另一个从抓包工具到服务器),并且抓包工具可以解密和重新加密数据,从而查看明文内容。
- 证书信任: 要执行上述的中间人攻击,抓包工具需要客户端信任其自签名的证书。这意味着在客户端设备上(如浏览器或移动设备)需要手动安装抓包工具的证书。一旦安装,抓包工具就可以解密HTTPS流量并将其显示为明文。
动画,前端怎么用动画实现颜色渐变
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.gradient-box {
width: 200px;
height: 200px;
background-color: red; /* 初始颜色 */
animation: gradientChange 3s infinite alternate; /* 动画 */
}
@keyframes gradientChange {
0% { background: red; } /* 起始颜色 */
100% { background: blue; } /* 结束颜色 */
}
</style>
</head>
<body>
<div class="gradient-box"></div>
</body>
</html>
npm, cnpm, yarn, pnpm的区别
npm, cnpm, yarn, 和 pnpm 都是用于Node.js项目的包管理器,它们的主要功能是安装、更新、卸载和管理项目依赖。尽管它们有相似的目标,但各自有一些区别:
- npm (Node Package Manager) :
-
- npm 是 Node.js 自带的官方包管理器。
- 它是最原始的包管理器,用于从npmjs.com仓库下载和安装模块。
- npm 命令可以用于安装、更新、发布、搜索和卸载包。
- npm 的安装速度相对较慢,因为它采用串行方式安装依赖,即按顺序逐个安装依赖包。
- cnpm (China NPM) :
-
- cnpm 是基于 npm 的镜像,主要针对中国用户,以解决访问npm官方仓库速度慢的问题。
- 它使用阿里云的服务器作为npm的镜像,从而加快了在中国境内的下载速度。
- 使用 cnpm 的命令与 npm 相同,只是源换成了国内的镜像。
- cnpm 不是官方工具,但它对于提高中国开发者的工作效率很有帮助。
- yarn (Yet Another Resource Negotiator) :
-
- yarn 是由 Facebook 开发的包管理器,旨在解决 npm 的一些性能问题。
- 它支持并行安装依赖,这意味着它可以同时安装多个包,显著提高了安装速度。
- yarn 还提供了确定性安装(保证每次安装都是一样的)、离线模式以及更友好的用户界面等特点。
- yarn 也支持锁定文件(类似 npm-shrinkwrap.json),确保在不同环境中的一致性。
- pnpm (Poor man's npm) :
-
- pnpm 是另一个高性能的包管理器,它也支持并行安装依赖。
- pnpm 的主要特点是使用了链接依赖的方式,避免了重复安装相同版本的包,节省磁盘空间。
- pnpm 使用了虚拟链接(virtual linking)技术,使得每个项目都可以共享相同的包实例,而不会产生冲突。
- pnpm 的性能通常比 npm 和 yarn 更好,特别是在大型项目中。
Monorepo
Monorepo(单仓库)是一种软件工程实践,其中所有的项目代码,包括库、工具、服务和应用程序,都被存储在一个单一的版本控制仓库中。这种方式在大型组织中变得越来越流行,尤其是那些使用微服务架构或拥有多个紧密相关的项目的企业。
Monorepo 的主要优点包括:
- 简化依赖管理:所有项目共享一个根目录下的 package.json 文件,这可以简化依赖的管理和版本控制,避免不同项目间的版本不一致。
- 减少构建时间:由于所有项目都在同一个仓库中,构建系统可以利用缓存和并行化来减少整体构建时间。
- 统一的开发体验:所有团队成员都在同一个代码库工作,这有助于创建一致的编码标准和开发流程。
- 便于跨项目协作:开发人员可以更容易地在不同项目之间切换,因为所有东西都在同一个地方。
- 资源和代码重用:在同一个仓库中的代码可以更容易地被重用,减少了代码冗余。
然而,Monorepo 也有一些潜在的缺点:
- 仓库大小:随着项目数量和代码量的增长,单个仓库可能会变得非常大,影响到克隆和同步的速度。
- 权限管理复杂:如果不同的项目有不同的访问权限要求,管理单个仓库的权限可能会变得复杂。
- 潜在的构建冲突:由于所有项目共享相同的构建系统,如果有构建错误,可能会影响整个仓库的构建过程。
- 迁移成本:将多个独立的仓库合并到一个单仓库中,或者反过来将一个单仓库拆分成多个独立的仓库,都可能是一个耗时且具有挑战性的过程。
手机验证码登录,如何保证验证码是本次发送的,后端要如何维护
手机验证码登录是一种常见的身份验证方式,用于确保操作是由账户的合法持有者发起的。为了保证验证码是本次发送的,并且未被篡改或重放,后端需要采取一些措施来维护验证码的有效性和安全性。以下是一些关键步骤:
- 生成验证码:
-
- 验证码应足够随机,通常为数字或字母组合,长度一般为4-6位。
- 验证码的生成可以使用加密算法或随机数生成器来确保其不可预测性。
- 记录验证码和元数据:
-
- 将验证码以及相关元数据(如手机号、发送时间、有效期等)存储在数据库或内存缓存中(如Redis)。
- 每个验证码应该有一个唯一的标识符,可以是手机号+时间戳的组合或其他唯一标识。
- 设置有效期:
-
- 验证码应该有有限的有效期,例如5-10分钟,过期后自动失效。
- 后端在存储验证码时应该设置一个过期时间,这样可以自动清除过期的验证码,减少存储负担。
- 防止重放攻击:
-
- 验证码只能使用一次,一旦被正确使用后,应立即标记为已使用并在数据库中删除或失效。
- 后端应该检查验证码是否已经被使用过,避免重放攻击。
- 验证码发送频率限制:
-
- 对于同一手机号,限制在一定时间内发送验证码的次数,防止暴力破解或滥用。
- 实现IP地址或设备指纹的限制,进一步增加安全性。
- 前端验证:
-
- 前端在提交验证码之前,可以进行初步的格式校验,确保验证码符合预期的格式。
- 如果有图形验证码,前端也应该显示并要求用户输入,以防止自动化攻击。
登录鉴权,token为什么不存在cookie中
- 安全性提高:
-
- 防止CSRF(跨站请求伪造)攻击: Token如果存储在Cookie中,由于Cookie通常会随每个HTTP请求自动发送到服务器,这使得它容易受到CSRF攻击。攻击者可以通过恶意网页触发用户的浏览器向目标站点发送请求,而这些请求会自动携带用户的Session Cookie,从而可能被用于非法操作。然而,如果Token存储在客户端的内存中或者本地存储中(如localStorage/sessionStorage),并通过HTTP请求头(如Authorization头)显式地发送,那么它就不会受到CSRF的影响。
- 跨域问题:
-
- 避免CORS(跨源资源共享)限制: Cookie受同源策略的限制,这意味着它们不能跨域共享。然而,Token可以通过请求头在不同的域名之间传递,这对于现代Web应用中常见的SPA(单页应用)和API分离架构尤其重要。
- 无状态性:
-
- 简化服务器端状态管理: Token通常设计为自我包含的,意味着所有必要的信息,包括用户身份和权限,都被编码在Token中。这允许服务器在验证Token时不需要查询数据库或保持会话状态,提高了可伸缩性和性能。
- 移动端友好:
-
- 适应移动设备: 移动端应用通常不使用Cookie进行身份验证,因为它们可能没有传统的HTTP会话环境。Token可以很容易地在各种设备和平台上使用,而无需依赖特定的Web浏览器特性。
- 易于撤销:
-
- 更灵活的权限控制: Token可以包含一个过期时间,一旦过期,Token就变得无效。这比管理服务器端的会话状态提供了更细粒度的控制。
黑客入侵了你本地的dns服务器,然后黑客自己的病毒网站使用了跟合法网站同样的域名,https还能防得住吗
当黑客入侵了你的本地DNS服务器或DNS解析途径,并将合法网站的域名解析指向他们自己的恶意网站时,这种攻击被称为DNS缓存中毒或DNS劫持。在这种情况下,HTTPS本身的设计仍能提供一定程度的保护,但是保护机制的效果取决于攻击的具体方式和用户的警觉性。
HTTPS协议通过SSL/TLS证书来验证网站的身份,确保数据在客户端和服务器之间的传输是加密的,并且确保用户访问的是真正的服务器而不是中间人(MITM)攻击中的假冒服务器。当你尝试访问一个HTTPS网站时,你的浏览器会检查服务器的证书,并确认它是由一个可信的证书颁发机构(CA)签发的。如果证书是有效的并且域名匹配,浏览器就会建立一个安全的连接。
然而,在DNS缓存中毒的情况下,你的DNS请求被重定向到了一个恶意服务器,而这个服务器也可能拥有一个证书。这里有几种可能的情况:
- 合法证书:如果黑客能够获得一个合法的证书(这通常是通过欺骗或攻破CA实现的),那么HTTPS可能无法识别这是一个恶意网站。但是,这种情况下证书颁发机构应该能够追踪并撤销该证书,一旦证书被标记为不信任,用户浏览器会警告用户证书已被吊销。
- 自签名证书:如果黑客使用的是自签名证书,大多数现代浏览器会发出警告,告知用户该证书不是由受信任的CA颁发的。除非用户明确选择信任这个自签名证书,否则HTTPS会阻止用户访问网站。
- 域名不匹配的证书:即使黑客能够获得一个合法证书,但如果没有正确的域名,浏览器也会检测到域名和证书中的域名不匹配,并给出警告。
web worker 和 service worker 的异同
Web Worker 和 Service Worker 都是在浏览器环境中运行的后台脚本,但它们的设计目的、应用场景和功能上有显著的不同:
Web Worker:
- 定义:Web Worker 是一种浏览器内多线程技术,它允许JavaScript在独立于主线程(UI线程)的后台线程中运行,以执行耗时的操作,如计算密集型任务,而不阻塞用户界面。
- 功能:
-
- 运行长期或短期的后台任务,如图像处理、大数据计算等。
- 通过postMessage()和onmessage事件与主线程通信,交换数据。
- 可分为两类:专用Worker(Dedicated Worker)和共享Worker(Shared Worker),前者仅服务于创建它的页面,后者可以由同一源下的多个页面共享。
Service Worker:
- Service Worker 是一种特殊的 JavaScript 脚本,它作为浏览器与网络之间的代理层,运行在浏览器的后台。Service Worker 允许开发者实现一系列强大的功能,包括离线缓存、缓存管理、请求拦截、推送通知、后台同步和其他高级网络功能。
- 离线缓存:通过Cache API,Service Worker可以提前缓存资源,使得网页在离线状态下仍能加载部分或全部内容。
- 网络代理:它可以充当网络中间人,控制页面发起的网络请求,选择性地返回缓存内容或转发至服务器获取最新数据。
- 推送通知:Service Worker 可以接收推送消息,并显示通知给用户,即使应用不在前台运行。
- 独立的缓存空间:Service Worker为每个源提供独立的缓存空间,不受HTTP缓存配额的限制。
- PWA(Progressive Web Apps) :Service Worker 是 PWA 的关键技术之一,它帮助构建可安装、离线可用、快速加载的 Web 应用。
异同点:
- 相同点:二者都是浏览器环境中的后台脚本,均能够提高网页性能和用户体验,都采用异步通信机制来与主线程交互。
- 不同点:
-
- 用途:Web Worker主要用于解决JavaScript执行过程中的CPU密集问题,提升用户体验;Service Worker更多关注网络层面的优化,包括离线支持、网络请求的拦截与管理。
- 生命周期:Web Worker通常与创建它的页面绑定,页面关闭时可能会终止;而Service Worker注册成功后会在浏览器中持久化存在,甚至在没有相关页面打开时也可以继续运行,直到被显式注销或因存储空间不足等原因被浏览器自动清理。
- 通信方式:虽然都可以与主线程通信,但Service Worker因其网络代理的角色,其通信机制和应用场景更为丰富和复杂。
- 权限:Service Worker因其独特的网络代理功能,拥有比Web Worker更高的权限,可以控制网络请求的生命周期和响应内容。
一个服务器与浏览器之间的中间人角色,如果网站中注册了service worker那么它可以拦截当前网站所 有的请求,进行判断(需要编写相应的判断程序),如果需要向服务器发起请求的就转给服务器,如果 可以直接使用缓存的就直接返回缓存不再转给服务器。从而大大提高浏览体验。
http缓存和service worker缓存有什么区别?
HTTP缓存
HTTP缓存主要依赖于HTTP响应头中的缓存控制指令,如Cache-Control、Expires、ETag和Last-Modified等。这些指令由服务器在响应中发送,指示浏览器何时以及如何缓存资源。
- 缓存控制由服务器决定:服务器通过响应头控制缓存策略,如缓存有效期和条件缓存。
- 缓存资源有限制:HTTP缓存受制于浏览器的缓存配额,不同源共享同一个缓存空间。
- 缓存易被清除:用户可以轻易地通过浏览器设置手动清除HTTP缓存,或通过硬刷新(Ctrl+F5)强制浏览器忽略缓存。
- 缓存策略较静态:服务器的缓存策略在部署后很难动态调整,除非重新部署更改后的代码。
Service Worker缓存
Service Worker缓存通过Cache API实现,这是一种更高级的缓存机制,允许开发者在客户端编写逻辑来控制资源的缓存和获取。
- 细粒度控制:开发者可以在Service Worker中编写逻辑,决定哪些资源应该缓存,以及何时使用缓存或重新从网络请求资源。
- 独立的缓存空间:Service Worker为每个源提供独立的缓存空间,不受HTTP缓存配额的限制。
- 持久性和可靠性:Service Worker缓存的内容不容易被用户清除,提供了更高的持久性和可靠性。
- 动态缓存策略:开发者可以通过Service Worker的fetch事件处理函数实时调整缓存策略,实现更复杂的缓存逻辑,如缓存优先(Cache First)、网络优先(Network First)等模式。
- 离线支持:Service Worker可以提供离线访问的能力,即使在网络断开的情况下,也能从缓存中提供资源。
总结
HTTP缓存更适用于静态资源和简单场景,由服务器控制,而Service Worker缓存更适合复杂的应用,尤其是那些需要高度定制化缓存策略或支持离线访问的PWA(Progressive Web App)应用。Service Worker缓存提供了更多的灵活性和控制,但同时也需要开发者投入更多精力来编写和维护相关的逻辑。
PWA
什么是PWA
PWA全称是: Progressive Web Apps(渐进式网页应用)。这是 2016 年,Google I/O 大会上提出一个下一代web应用的概念。这并不是描述一个技术,而是一些技术的合集,能让你在使用 Web的时候感觉像是在使用 APP。
PWA能干什么
- 消息推送
- 主屏ICON,全屏访问
- 离线存储
pwa缓存的原理
为什么能实现缓存或者叫离线存储?核心就是利用浏览器service-worker另启一个线程,这个线程负责去监听所有https请求(注意是https),当发现某些资源是需要缓存下来的他会把资源拉取到浏览器本地,访问的时候拦截请求,不走网络请求,直接读取本地资源。这样资源相当于都是用户本地的资源,响应速度肯定飞快,还有就是资源都在用户浏览器里面,就算断了网,资源也都是能正常访问。
pwa缓存的缓存策略
上面说到某些资源是需要缓存。缓存多长时间?是永远走缓存还是永远走网络?还是一些特定的缓存策略的?下面介绍常见用的几种缓存策略:
cache-first
Cache-First策略会在有缓存的时候返回缓存,没有缓存才会去请求并且把请求结果缓存。也就是说,第一次页面加载跟普通页面加载没有任何区别的,第二次访问的资源是直接走了本地缓存数据的。
network-first
network-first 是一个比较复杂的策略。资源优先走网络,成功以后会把资源添加到缓存里面,当发现网失败就会回退读取缓存。这里面有一个点就是,多长时间算网络请求失败?这时候就需要配置一个超时时间,如果不配置回退缓存的时间就会比较长。这个时间根据自身项目而定。
service worker缓存有什么不太好的地方?service worker更新不及时怎么处理?
Service Worker 缓存的潜在问题
- 缓存更新问题:
-
- 版本控制难度:Service Worker 的更新需要特别处理,以确保新的更新可以替换旧的 Service Worker。如果不正确处理,可能会导致新旧版本共存,引起混乱。
- 即时生效问题:新的 Service Worker 更新后不会立即激活并接管所有打开的标签页。它需要等待所有相关页面关闭或通过特定的逻辑强制激活。
- 缓存过时风险:
-
- 数据同步问题:如果 Service Worker 缓存了动态数据,而数据在后台已经改变,缓存中的数据可能过时,导致用户看到的信息不准确。
- 缓存空间限制:
-
- 存储配额:尽管 Service Worker 有独立的缓存空间,但这个空间并不是无限的。过度缓存可能导致超出配额,进而影响缓存的有效性。
- 调试困难:
-
- 隐蔽性:Service Worker 在后台运行,调试可能比普通的 JavaScript 更具挑战性,尤其是在缓存相关的错误诊断上。
- 用户清理缓存:
-
- 不可控性:用户可以随时清除 Service Worker 缓存,这可能会影响应用的离线体验。
处理 Service Worker 更新不及时的方法
为了处理 Service Worker 更新不及时的问题,可以采取以下策略:
- 版本控制:
-
- 使用版本号或哈希值作为缓存名称的一部分,确保每次更新都使用新的缓存名称,从而促使浏览器替换旧的缓存。
- 强制激活新版本:
-
- 在 Service Worker 的 activate 事件中,清理不再需要的旧缓存,并调用 self.clients.claim() 来立即控制所有相关的窗口和标签。
- 使用 skipWaiting() :
-
- 在 Service Worker 的 install 事件中调用 self.skipWaiting() 可以跳过等待阶段,使 Service Worker 尽快成为激活状态。
- 监听 fetch 事件:
-
- 在 fetch 事件中检查资源是否是最新的,如果不是,可以从网络重新获取,同时更新缓存。
- 通知用户:
-
- 如果应用有重大更新,可以显示一个通知或弹窗,建议用户刷新页面或关闭并重新打开应用,以确保使用最新版本。
- 缓存有效性检查:
-
- 设定合理的缓存过期时间,或者使用 network-first 或 stale-while-revalidate 策略来确保缓存数据尽可能最新。
react中的useState可以记忆上一轮的变量,是基于闭包实现的吗?
下面是一个简单的useState示例:
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
在这个例子中,setCount函数是在Example组件的闭包中定义的,因此它能够记住和访问count的状态,即使组件被重新渲染。当按钮被点击时,setCount函数被调用,更新count的值,进而导致组件重新渲染,显示新的计数值。
background-color的作用范围一般是content + padding
正则
表示方法
方法一: new
var str = new RegExp(//)
方法二:字面量
var str = //
- 元字符:这些是具有特殊含义的字符,用于构造复杂的模式。常见的元字符包括:
-
- .:匹配任何单个字符(除了换行符)。
- ^:表示行的开始。
- $:表示行的结束。
- *:零次或多次重复前一个字符或组。
- +:一次或多次重复前一个字符或组。
- ?:零次或一次重复前一个字符或组。
- {n,m}:至少重复n次,至多重复m次。
- []:字符集,匹配其中任意一个字符。
- |:或运算符,匹配左边或右边的模式。
- ():分组,用于捕获或组合模式。
- \:转义字符,用于取消元字符的特殊含义,或引入特殊字符(如\n代表换行符)。
/ab/ 只要包含ab,就返回tr
/[ab]/ 只要包含a | b 就返回true
/^ab$/ 只能是ab
/^[ab]$/ 只能是a | b
/^[a-z]$/ 26英文字母任意一个
/^[^a-z]$/ 中括号里面有^,代表取反
/^(ab){3}$/ 小括号优先级最高,只能是ababab
/^ab{3}$/ 只能是abbb
| 或
\d 0-9
\D 取反
\w 数字,字母,下划线
\W 取反
str.replace(/激情/, '**') 替换
g 全局
i 忽略大小写
{1,} // 1到无穷
{1, } // 报错,不能加空格
想要判断字符串里是否有$,要加转义符\,否则报错
/$/
方法:
1,replace
在JavaScript中,String.prototype.replace() 方法用于在字符串中替换一些字符。这个方法接受一到两个参数,并返回一个新的字符串,原始字符串不会被修改。它的基本语法如下:
string.replace(searchvalue, replacevalue)
或者使用正则表达式:
string.replace(regexp, replacevalue)
- searchvalue:这是你想要查找并替换的子字符串或正则表达式。
- replacevalue:这是用来替换searchvalue的字符串或函数。
基本用法
当你使用一个字符串作为searchvalue时,replace()方法只会替换第一个匹配的子字符串:
let str = "Hello World";
let newStr = str.replace("World", "JavaScript");
console.log(newStr); // 输出 "Hello JavaScript"
使用正则表达式
如果你使用正则表达式作为searchvalue,并且在正则表达式中包含g标志,那么replace()方法会替换所有匹配的子字符串:
let str = "hello world, hello universe";
let newStr = str.replace(/hello/g, "hi");
console.log(newStr); // 输出 "hi world, hi universe"
使用函数作为替换值
replacevalue也可以是一个函数,这个函数会被调用一次,对于每个匹配的子串,函数的参数如下:
- match:与正则表达式匹配的子字符串。
- ...groups:如果正则表达式有括号分组,则这些分组会作为额外的参数传入。
- offset:匹配子字符串在原字符串中的位置。
- string:原字符串。
函数的返回值将被用作替换值:
let str = "hello world";
let newStr = str.replace(/world/g, function(match) {
return match.toUpperCase();
});
console.log(newStr); // 输出 "hello WORLD"
例子,把 f-ejE-ieo-jiee格式的字符串转成驼峰, 用正则, 要求fEjeIeoJiee
let str = "f-ejE-ieo-jiee";
let newStr = str.replace(/(\w)-(\w)/g, (match, groups, groupss) => {
console.log(match, groups, groupss); // 第一轮遍历,f-e, f, e
// 有几个括号分组,就有几个...groups的参数。如上,有两个,所以有两个参数
let sets = ''
sets += groups.toLowerCase()
sets += groupss.toUpperCase()
return sets
});
console.log(newStr); // fEjeIeoJiee
2, match
用法: str.match(//)
找到则返回找到的字符,否则返回null
let aa = 'ofejwjeef'
console.log(aa.match(/a/)); // null
console.log(aa.match(/e/)); // [ 'e', index: 2, input: 'ofejwjeef', groups: undefined ]
console.log(aa.match(/e/g)); // ['e', 'e', 'e']
3, test
用法: //.text(str)
匹配则返回true, 否则false
let aa = /e/
console.log(aa.test('jlw')); // false
console.log(aa.test('ofejwjeef')); // true