尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
微信小程序字符串处理全攻略:split/substring/concat/charAt实战
做小程序开发这两年多我最大的感受就是字符串处理其实占了日常逻辑的三成以上。不管是接口返回的数据格式整理、用户输入的表单校验还是列表渲染前的加工翻来覆去就是那些方法——split切割、substring提取、concat拼接、charAt取字符。但恰恰是这些基础方法很多人在真机调试时才发现用错了iOS上一个效果、Android上一个效果要么多一个空格要么截取长度不对。这篇就专门把微信小程序里JS字符串操作的方法梳理一遍重点讲清楚每个方法的边界行为和真实场景下的取舍。我尽量用通俗的大白话配合代码和踩坑经验来写让大家看完能直接用在自己的项目里。1. split切割接口数据解析最常用的方法但很多人没用对1.1 split的基本用法与分隔符陷阱split 方法做的事情很简单把一个字符串按照你指定的分隔符拆成数组。项目里最常见的场景就是把后端返回的逗号分隔字符串转成数组来渲染。// 模拟小程序里从接口拿到的数据 const goodsIds 101,102,103,104; const goodsArr goodsIds.split(,); console.log(goodsArr); // [101, 102, 103, 104]从上面代码看一切都很顺利对吧但实际项目里有个很隐蔽的坑后端返回的字符串经常带着换行符和空格尤其当这些数据是从Excel导入或者由用户手动填写的表单拼接起来的时候。const input 102, 103,104; // 注意102后面有个空格 const arr input.split(,); console.log(arr); // [102, 103, 104] —— 第二个元素带了空格这种脏数据如果直接拿来渲染或者做比对就会出问题。所以我在项目里的习惯是split前面先trim掉首尾空格需要的话再配合map方法做二次清理。const arr input.trim().split(,).map(item item.trim());另外split还支持传正则表达式作为分隔符这个在处理多分隔符混合的场景下特别好用。比如一个地址字符串里面可能既有逗号又有中文顿号const stationStr 北京站,上海站、广州站; const stations stationStr.split(/[,、]/); console.log(stations); // [北京站, 上海站, 广州站]1.2 limit参数和空字符串边界split的第二个参数是limit用来限制返回数组的长度。我印象最深的一次是处理一个日志分割的场景后端日志内容是日期|级别|内容但内容字段里也可能包含竖线符号。这时候直接split会把内容也拆碎所以我只用limit限制成三段再把后面内容手动合并回去。const log 2024-01-15 10:00:00|INFO|用户点击了支付按钮|订单号为123456; const parts log.split(|, 3); console.log(parts); // [2024-01-15 10:00:00, INFO, 用户点击了支付按钮|订单号为123456]注意在很多语言里字符串分割成数组后数组后的元素不能像某些语言那样直接访问字符串的字。这里需要留意微信小程序用的是JavaScript引擎iOS上是JavaScriptCore、Android上是V8这些行为都遵循标准ECMAScript规范。还有一个边界情况经常被忽视——空字符串和分隔符不存在时const emptyStr ; console.log(emptyStr.split(,)); // [] const noComma abc; console.log(noComma.split(,)); // [abc]当字符串为空时split返回的是包含一个空字符串的数组而不是空数组。这个陷阱坑过我一次我在做购物车批量删除时如果用户全部取消后端返回一个空的sku字符串直接调用split后得到数组长度是1而不是0导致一个无意义的请求被发出。后来我改成先判断字符串是否为空再处理。2. 截取字符串三兄弟substring、slice、substr到底应该用哪个2.1 三个方法的行为对照标题里提到的substring是提取字符串的经典方法但实际开发中很多人被substring、slice、substr这三个名字接近的方法搞得晕头转向。先看一张对比表方法语法负值处理参数互换标准性substringstr.substring(start, end)负数会被当作0若startend会自动交换ECMAScript标准slicestr.slice(start, end)负数表示从末尾倒数不会交换返回空串ECMAScript标准substrstr.substr(start, length)负数从末尾倒数第二参数是长度非标准Web兼容保留我强烈建议新项目里直接忽略substr这是非标准方法虽然微信小程序两个平台都支持但出问题的概率始终存在而且语义容易混淆。在substring和slice之间二选一我倾向于always用slice除非有特殊理由。2.2 负值处理和截取场景slice和substring最大的差异在于负值参数的处理const code ABC12345; // slice支持负数从末尾倒数 console.log(code.slice(-3)); // 345 console.log(code.slice(0, -3)); // ABC12 // substring不支持负数当做0处理 console.log(code.substring(-3)); // ABC12345整串返回 console.log(code.substring(0, -3)); // 这里因为-3被当成0而start(0)和end(0)相同结果是空串上面这个例子很有代表性。在小程序里截取订单号后三位、或者是倒序截取商品编码的场景用slice的负数语义直接搞定不需要先算length再减。2.3 实际场景手机号脱敏与昵称截断先看一个手机号脱敏的需求。很多小程序为了提高用户安全感会在订单详情页展示脱敏后的手机号比如138****1234。这个用slice配合substring可以优雅实现const mobile 13812341234; const masked mobile.slice(0, 3) **** mobile.slice(-4); console.log(masked); // 138****1234昵称截断场景也很典型。用户昵称可能是中文、英文混合甚至带表情符号。如果直接按length截断中英文混排会截错如果不管长度直接渲染超过两行的昵称会破坏布局。我的做法是结合Array.from来统计字符这个后面细说。处理字符串截断本身// 截取前10个字符超过部分追加省略号 const nickname 这个昵称真的特别特别长超过十个字了; let display nickname.slice(0, 10); if (nickname.length 10) { display ...; } console.log(display); // 这个昵称真的特别特别长超...但如果你要按显示宽度做截断就得考虑中英文宽度差异了这个我放到后面的章节专门展开。2.4 substring的乱序自动交换特性substring有一个容易让人困惑但也很实用的特性如果start大于end它会自动交换两个参数。看这个例子const str hello; console.log(str.substring(3, 1)); // el console.log(str.slice(3, 1)); // 空串这个特性在动态计算截取位置时能省事很多但也很容易造成结果和预期不一致但又不报错的问题。我的建议是不要依赖这个自动交换特性代码里手动保证startend。否则过几个月你自己回来维护根本想不起来当时到底传的什么。3. 字符串拼接加号、concat与join的性能和场景对比3.1 加号拼接为什么在循环里不划算有人说拼接字符串用加号不就行了吗是的在短字符串拼接场景下加号确实最直观。但如果你在循环里频繁拼接性能问题就会体现出来。字符串在JavaScript里是不可变的每次用加号拼接都会产生一个全新的字符串。如果在一个大循环里直接写result item本质上每次循环都在创建一个新字符串并销毁旧字符串循环次数一多创建和销毁的次数就非常多。// 不推荐写法大量循环拼接 let result ; for (let i 0; i 1000; i) { result JSON.stringify(resultData[i]) ,; }在小程序里这种写法可能让页面出现明显卡顿。更好的方式是先把片段装进数组一次性join起来// 推荐写法 const chunks []; for (let i 0; i 1000; i) { chunks.push(JSON.stringify(resultData[i])); } const result chunks.join(,);3.2 join其实不是字符串方法联合使用场景很广这里要特别澄清一个概念标题里说join合并字符串严格来说join是数组的方法不是字符串的方法。它在字符串处理中之所以这么常用是因为我们经常要把分词后的数组重新合并成字符串——比如把数组变回逗号分隔的字符串再传给后端。// 数组重组成字符串 const selectedIds [101, 102, 103]; const submitData selectedIds.join(,); console.log(submitData); // 101,102,103join还可以直接拼接的时候加前缀后缀或者利用空字符拼接消除中间值const keyArr [item, list, detail]; const path keyArr.join(/); console.log(path); // item/list/detail另外我要提一个比较骚的用法用Array(4).join(a)生成重复字符串。早期的ECharts和很多库都用这种方式来代替循环拼接// 生成10个- const line new Array(11).join(-); console.log(line); // ----------不过现在有ES6的String.prototype.repeat方法了在小程序基础库较新版本下也可以直接用-.repeat(10)更清晰直观。3.3 concat方法的适用与不适用concat是数组和字符串都有的方法字符串的concat和加号的功能一模一样甚至多数情况下不如加号直观const a hello; const b world; console.log(a.concat(b)); // helloworld console.log(a b); // helloworld但有场景我会特意用concat需要拼接多个变量并且中间不需要额外分隔符时concat比一连串加号要好读懂。另外concat支持一次传多个参数const prefix [订单]; const target 商品详情; const suffix 已生成; const report prefix.concat(target, suffix); console.log(report); // [订单]商品详情已生成不过说实话现在ES6模板字符串反引号已经非常普及小程序的WXS也支持基础的模板字符串语法很多场景我直接用反引号const report ${prefix}${target}${suffix};模板字符串的优势是可读性极强一眼就能看出拼接结构。所以在渲染前拼展示文案这种场景我基本都是模板字符串优先。在很多真实项目里渲染展示文案更常见的做法是在WXML里直接用大胡子语法拼view{{prefix target suffix}}/view但注意在WXML的大胡子表达式里只能使用有限的运算不能调用字符串的方法。所以需要函数处理的逻辑最好放进JS里先算好或者使用WXSWeiXin Script来做数据加工。WXS里支持的字符串方法和JS是同一个规范子集但有一点不同WXS不支持ES6语法所以模板字符串在WXS里不可用只能老老实实用concat或加号。4. 根据索引取字符charAt、charCodeAt与索引访问的关系4.1 charAt和str[index]的区别charAt方法返回指定位置的字符和直接用下标访问很像但有个细微差异当索引越界时charAt返回空字符串而下标访问返回undefined。const code ABC; console.log(code.charAt(1)); // B console.log(code[1]); // B console.log(code.charAt(5)); // console.log(code[5]); // undefined别小看这个差异。在小程序的开发环境里一旦数据出现越界用下标访问很容易造成undefined直接参与拼接的问题页面上出现undefined字样。用charAt取不到值时至少返回的是一个空字符串拼接出来的文案不会出现难看的undefined。4.2 实战案例身份证号和订单号的处理我在做一个会员中心的小程序时需要从身份证号倒数第二位判断性别。如果用户输入不足15位直接越界就会出问题const idCard 510101199001011234; // 倒数第2位奇数男偶数女 const genderBit idCard.charAt(idCard.length - 2); if (genderBit) { const gender parseInt(genderBit, 10) % 2 1 ? 男 : 女; }如果前面用idCard[idCard.length - 2]万一idCard为空字符串拿到的就是undefinedparseInt(undefined, 10)的结果是NaN性别判断就会失准。而charAt在空字符串情况下返回更容易被意识到的分支处理掉。这里还有一个开发小技巧想拿到某个unicode编码值用charCodeAtconst keyStr A; console.log(keyStr.charCodeAt(0)); // 65小程序里做字符串加密或者hash的时候charCodeAt是非常底层的骨干方法比如把字符串转成字节数组function strToBytes(str) { const bytes []; for (let i 0; i str.length; i) { bytes.push(str.charCodeAt(i)); } return bytes; }4.3 中文和emoji字符的截取坑这里必须展开讲一个真实踩坑经验charAt和length处理中文字符时一个中文字符在JavaScript里length按1计数看起来没什么问题但遇到emoji表情或者一些生僻字比如某些部首组合length就可能变成2甚至更多。因为JavaScript字符串本质上是以UTF-16编码的大部分汉字属于基本平面length1但emoji和某些辅助平面的汉字采用代理对表示length2。如果你用charAt去遍历每个字符会看到一些乱码。const emojiStr ab; console.log(emojiStr.length); // 4而不是3 console.log(emojiStr.charAt(1)); // 这里输出的是半个代理项显示乱码 console.log(Array.from(emojiStr)); // [a, , b] 正确按返回值划分所以做用户昵称截取时我最稳妥的方式是用Array.from先把字符串转成真正的字符数组再做切片function truncateNickname(str, maxLen) { const chars Array.from(str || ); if (chars.length maxLen) return str; return chars.slice(0, maxLen).join() ...; }这个函数在小程序的项目里非常通用处理中英文混排和emoji都不会出乱子。要特别注意Array.from在小程序的基础库版本较老时可能不支持建议在app.js里挂一个polyfill或者自己写一个split迭代器。5. 字符串方法组合拳replace、trim、indexOf与综合实战5.1 常用配套方法梳理除了标题里列的split、join、concat、charAt、substring日常开发中还有一个高频组合replace、trim、indexOf/includes。在很多人的印象里这些方法太简单不值得专门写但我在小程序开发群里答疑时就发现很多人对replace的理解停留在只替换第一个匹配层面。const text 小米手机-红色-64G; const result text.replace(-, :); console.log(result); // 小米手机:红色-64G 只替换了第一个如果要用replace替换所有匹配项必须传正则表达式并加g修饰符或者用replaceAll注意基础库版本const resultAll text.replace(/-/g, :); console.log(resultAll); // 小米手机:红色:64Gtrim方法用来移除字符串首尾空白字符。在小程序表单处理里用户输入前后附带的空格可以说是最常见的脏数据来源。用户可能在姓名后面不小心多打了一个空格提交给后端就会校验失败。所以我通常在表单提交前统一做trim处理const nickname nicknameInput.trim();indexOf用来判断某个子串是否存在返回值是首次出现的索引如果不存在返回-1。新版本也可以直接用includes得到布尔值语义上更清晰const orderNo PO202401150001; console.log(orderNo.indexOf(PO) 0); // true console.log(orderNo.includes(2024)); // true这里有个小技巧判断是否以某个前缀开头用str.startsWith(PO)更接近直白语义后面也可以复用。5.2 综合实战小程序表单实时校验结合上面的方法写一个典型的表单实时校验例子。比如用户在input里输入手机号oninput事件里实时校验格式、过滤非法字符handlePhoneInput(e) { let phone e.detail.value; // 1. 去掉首尾空格 phone phone.trim(); // 2. 过滤掉非数字字符但保留号处理区号 phone phone.replace(/[^\d]/g, ); // 3. 限制最长长度用slice截取 phone phone.slice(0, 20); // 4. 判断是否为合法手机号格式 const isValid /^1[3-9]\d{9}$/.test(phone); this.setData({ phone, phoneValid: isValid }); }这段代码里使用replace配合正则做了一个过滤动作使用slice做了长度限制使用正则进行格式校验。看起来简单但每一步的背后都藏着边界处理不限制长度用户可能粘贴一大串不过滤符号后端会报警首尾空格不trim会出现188... 这种看起来正常但实际多了空格的数据。5.3 字符串分组格式化千分位处理再分享一个进阶一点的例子——金额千分位格式化。小程序里做价格展示时后端返回的往往是纯数字或者字符串数字直接渲染在页面上是1234567.89观感非常不友好我们通常要格式化成1,234,567.89。这个场景就是split、join、replace的组合操作function formatPrice(value) { const str String(value); const parts str.split(.); const intPart parts[0]; const decPart parts[1] ? . parts[1] : ; // 给整数部分加千分位 const formattedInt intPart.replace(/\B(?(\d{3})(?!\d))/g, ,); return formattedInt decPart; } console.log(formatPrice(1234567.89)); // 1,234,567.89这段正则的核心是\B(?(\d{3})(?!\d))它的逻辑是在后面跟着3的倍数个数字且不是最后一个数字的非单词边界位置插入逗号。如果看不懂正则没关系关键是理解这种拆分-替换-合并的字符串处理思路实际项目里完全可以套用。6. 小程序环境中的字符串操作兼容性问题、性能注意点与调试建议6.1 大小端平台差异与基础库版本微信小程序在iOS和Android上分别跑在JavaScriptCore和V8引擎上绝大部分ECMAScript标准方法行为都是一致的。但有两个注意点值得单独说第一String.prototype.replaceAll方法在较老的基础库上不可用我建议统一用str.replace(/xxx/g, )这种正则全局替换写法既能兼容两平台也无需担心基础库版本。第二模板字符串在WXS中不可用。WXS的语法更像ES5不支持let、const、模板字符串这些ES6特性。如果数据需要在WXML渲染前做处理尽量在Page的JS逻辑里做更好的方案如果依赖WXS做轻量处理记得只能用常规写法。还有一个容易被忽略的性能问题不要在大循环里调用split和join处理超长字符串。比如把一个几百KB的日志字符串切成数组逐行处理在小程序里会产生明显的卡顿。我的经验是两条路要么在服务端就处理好数据小程序直接拿处理结果要么使用分批处理的方式用setTimeout或wx.nextTick把大循环切片处理保证界面不阻塞。6.2 字符串不变的特性与引用关系JavaScript字符串是不可变的这个特性在小程序里也适用。很多初学的小程序开发者会写类似下面的代码以为字符串会被原地修改let userInput abc; userInput.trim(); // 这里trim的返回值没有赋值回去 console.log(userInput); // abc原字符串没有变要修改字符串变量必须把方法的返回值赋给变量。这也是为什么前面每个场景我都强调用变量接住处理后的结果。从调试角度看遇到字符串处理前后没变化第一反应应该是检查是不是忘了接收返回值。我还见过一个真实案例某开发者在onLoad里解析页面参数params的值转成了字符串想切割但是直接用const data params.split(,)然而params其实不是字符串类型而是数组类型导致split不是函数页面白屏。所以解析URL参数时要先String(params)再处理这个习惯非常重要。6.3 实际场景中的格式化与单位转换字符串操作并不只是切切拼拼很多时候要跟数字、日期打交道。我在做一个小程序商城时后端返回的时间戳需要转成2024-01-15 10:30:00格式核心是先把时间戳转成Date对象再拼字符串function formatDateTime(timestamp) { const date new Date(timestamp); const year date.getFullYear(); const month String(date.getMonth() 1).padStart(2, 0); const day String(date.getDate()).padStart(2, 0); const hours String(date.getHours()).padStart(2, 0); const minutes String(date.getMinutes()).padStart(2, 0); const seconds String(date.getSeconds()).padStart(2, 0); return ${year}-${month}-${day} ${hours}:${minutes}:${seconds}; }这里用到了padStart方法它也是字符串方法里非常实用的一个用来补零、补齐位数都很方便。在小程序基础库上padStart和padEnd都是支持的不过老版本可能没有稳妥起见也可以自己写一个补零函数function padZero(n) { return (n 10 ? 0 : ) n; }6.4 从工具函数沉淀到公共库在小程序项目的开发过程中我习惯把这些字符串处理函数沉淀到一个单独的工具文件里例如utils/string.js然后在需要的页面直接require。比较通用的几个函数包括手机号脱敏、昵称截断按字符数、金额千分位格式化、时间格式化、去除字符串中所有空格、判断是否为纯数字等。这些函数不依赖小程序API纯JavaScript实现可以在小程序中直接复用也能够在单元测试环境里单独验证。提前把这套公共函数沉淀好后续新页面处理数据时就不用每次重写也可以减少因为字符串边界条件没处理好而出现的线上bug。最后的实战建议如果要我说一句对小程序字符串处理最重要的体会就是写业务逻辑之前先确认变量的类型和值可能出现的边界情况——是不是空字符串、带不带空格、字符编码是不是代理对、有没有换行符。大多数方法无效或者页面显示异常不是方法本身有问题而是入参和预期不符。建议在做字符串处理时养成这几个习惯接收后端数据先用String()或者typeof判断类型trim以后再split涉及中英文混排和emoji的截断用Array.from转数组再处理所有会返回新字符串的方法记得用变量接住结果能用模板字符串的地方不要手动拼接一长串加号。字符串方法本身都很简单真正体现功力的是在具体业务场景里选择和组合它们。希望这篇梳理对大家有帮助后面如果在自己的小程序开发里遇到什么奇怪的字符串问题也可以多往边界条件和平台兼容性上面想想。
RELATED

相关推荐

imgaug 0.4.0 缺陷修复解析:Affine 的 translate_px 为何会误当 translate_percent 使用

imgaug 0.4.0 缺陷修复解析:Affine 的 translate_px 为何会误当 translate_percent 使用

数据增强计算机视觉图像处理机器学习 【免费下载链接】imgaug Image augmentation for machine learning experiments. 项目地址: https://gitcode.com/gh_mirrors/im/imgaug 点击查看 免费下载 本篇围绕 imgaug 0.4.0 周期内的一份缺陷修复记录展开:Af…

📅 2026/10/14 8:15:19
VR触觉手套如何革新飞机货舱门操作培训:系统构建与实战指南

VR触觉手套如何革新飞机货舱门操作培训:系统构建与实战指南

刚把一套VR触觉手套训练程序落地到某航空货运公司的地勤培训体系里,带第一批学员跑完整个循环之后,有个学员复盘时跟我说了一句话:他第一次在虚拟货舱里推货舱门手柄时,手套传来的那股阻尼感让他下意识握得更紧,而画面…

📅 2026/10/14 8:15:19
大模型API统一网关liteLLM:模型路由、密钥管理与成本控制实战

大模型API统一网关liteLLM:模型路由、密钥管理与成本控制实战

干这行最头疼的事,不是模型效果不好,而是“调接口调得想骂人”。手上一堆项目要接不同厂家的模型,有的用这种方式鉴权,有的要那种格式传参,A家的输出和B家的输出还不完全兼容。原本半小时能写完的功能,光对…

📅 2026/10/14 8:15:19
MORE NEWS

更多资讯

📰

栈与表达式求值:双栈法及中缀转后缀的机试实战

如果你正在准备某通信科技公司的机试,“实现一个简单的计算器”这道题几乎绕不开。我第一次在在线笔试系统里看到它时,心里想:不就是小学算术吗?真正把代码写出来才发现,它考的不是你会不会算数,而是你对待…

📰

小白做题日记(3)洛谷P5440 洛谷P1378

1.https://www.luogu.com.cn/problem/P5440 (预处理枚举字符串匹配日期相关) 出现这种日期问题需要考虑的问题:1.每个月的日期是多少天。2.一共12个月。3.平年闰年的处理(二月份平年是28天,闰年时29天)。 不能直接枚…

📰

Scala递归类型:原理、实现与应用场景解析

1. 递归类型的概念与价值在Scala类型系统中,递归类型(Recursive Types)是一种允许类型在其自身定义中引用自身的特殊构造。这种自指涉的特性为建模复杂数据结构提供了强大的表达能力。想象一下俄罗斯套娃的结构——每个套娃内部都包含一个更小…

📰

MDO3024 示波器 + LabVIEW 能测什么?

Tektronix MDO3024 是泰克的混合域示波器,模拟通道之外还带数字通道和频谱分析能力。一台仪器三块能力,但要让它自动跑起来才算数。01 这台设备在哪些场景里干活嵌入式调试。 一路模拟信号配八路数字总线,要看时序关系——谁先谁后、建立保持…

📰

高校职称评审管理系统设计与实现

1. 项目背景与核心价值这个职称评审管理系统是典型的教务管理类信息化解决方案,主要面向高校、科研院所和企事业单位的人力资源部门。我在参与某高校职称评审流程优化项目时,深刻体会到传统纸质申报的痛点:材料容易丢失、审核进度不透明、跨部…

📰

云计算课件开发实战:从抽象概念到可运行实验环境

简介:这份云计算课件面向高校计算机相关专业学生、云计算入门学习者及需要备课的教师,系统梳理云计算从概念到落地的完整知识框架,帮助读者建立对云服务体系与底层技术的整体认知。资源包共1个文件,为1份ppt演示文稿,压…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬