JS/TS 编码规范实战:Vue 场景变量 / 函数 / 类型标注避坑|编码语法规范篇

JS/TS 编码规范实战:Vue 场景变量 / 函数 / 类型标注避坑|编码语法规范篇 【Vue/JS/TS】【前端日常开发】从【变量声明/函数写法/类型标注】到【落地实操】彻底搞懂【前端可维护代码】的最佳写法避开团队协作高频坑 文章目录一、先定一个总原则让代码回答 3 个问题二、变量声明const 优先let 必要别用 var2.1 规则一默认用 const能不变就不变2.2 规则二对象/数组“内容可变”要自觉2.3 规则三作用域要清楚尽量避免“跨块复用同名”2.4 变量命名你会在 Vue 里反复用到三、函数写法优先“清晰 可复用”区分声明与箭头3.1 规则一函数做工具就写“函数声明”做回调就写“箭头函数”3.2 规则二箭头函数逻辑简单就用隐式返回复杂就用大括号 显式 return3.3 规则三参数处理清晰默认值优先避免“神秘 undefined”3.4 规则四尽量“早返回”减少深层嵌套3.5 规则五纯函数优先副作用要“隔离”四、TS 类型标注标注边界能推断就推断别滥用 any4.1 规则一不要到处写类型优先让 TS 推断简单情况4.2 规则二公开函数/工具函数建议给入参和返回值4.3 规则三类型别写成“装饰品”要覆盖真实约束4.4 规则四联合类型要配合“判别方式”或类型保护type guard4.5 规则五空值处理要“可读”优先 ?? / 可选链 ?.4.6 规则六尽量少用类型断言as它只能当“最后一层保险”五、一套完整实战示例Vue 场景下的变量/函数/类型怎么选5.1 TS 版本推荐写法简洁又规范5.2 反例同样的需求用 JS/TS 常见写法会怎么“变味”六、日常落地清单写完代码前你可以自检这 6 条 系列模块导航同学们好我是 Eugene尤金一名多年中后台前端开发工程师。Eugene 发音 /juːˈdʒiːn/大家怎么顺口怎么叫就好很多前端开发者都会遇到一个瓶颈代码能跑但不够规范功能能实现但维护起来特别痛苦一个人写没问题一到团队协作就各种混乱、踩坑、返工。想写出干净、优雅、可维护的专业代码靠的不是天赋而是体系化的规范 真实实战经验。这一系列《前端规范实战》我会用大白话 真实业务场景不讲玄学、不堆理论只分享能直接落地的规范、标准与避坑指南。帮你从「会写代码」真正升级为「会写优质、可维护、团队级别的代码」。做了 7 年前端后我越来越确定规范不是“为了显得严谨”而是为了在你每天写的代码里减少歧义、降低出错率、让团队更快读懂。尤其是 Vue 项目里代码往往会被拆到很多文件、很多watch/effect/computed里变量声明、函数写法、类型标注只要稍微“不自洽”后面就会反复踩同一类坑。这篇文章不讲玄学底层原理只讲“日常写代码到底怎么选、为什么这么选、踩坑会踩在哪”并且每个规则都给出小白也能照着用的完整示例。你可以直接把它当成“编码时的选择题”。一、先定一个总原则让代码回答 3 个问题写任何一段 JS/TS 代码都尽量让读者包括未来的你在 3 秒内看懂这段代码的“东西”是什么变量/参数/返回值的语义这段代码会不会变化变量是否可变、函数是否有副作用类型上有哪些约束TS 能推断就推断推断不了就明确标注边界接下来我们按你关心的 3 个核心语法部分来落地变量声明 / 函数写法 / 类型标注。二、变量声明const优先let必要别用var2.1 规则一默认用const能不变就不变在 JS 里变量声明最容易带来的 bug 是“以为不会变结果被改了”然后你在别处使用了旧值出现错位、渲染异常、计算结果不对。推荐“只赋值一次”的变量用const“需要重新赋值”的变量用let**不使用 **var作用域、提升行为更容易造成误解反例可读性差 未来容易被改lettotal0;for(constpofproducts){totalp.price;}totaltotal*1.1;// 未来改动时很容易忽略“total”本来不该变正例更清晰total 的含义更稳定consttotalproducts.reduce((sum,p)sump.price,0);constdiscountTotaltotal*1.1;⬆ 返回目录2.2 规则二对象/数组“内容可变”要自觉很多人以为const obj {}就代表“不能改”这不成立。const只是保证变量绑定不被重新指向但对象内部仍然可以被改。你可以这样理解const变量名别换指向不要再obj xxx对象内部修改要么明确接受可变要么尽量用不可变写法更适合状态管理反例隐蔽的可变constuser{name:Alice,age:20};user.age21;// 读者可能以为你在做不可变更新但你在原地修改正例不可变更新更利于追踪变更constuser{name:Alice,age:20};constupdatedUser{...user,age:21};⬆ 返回目录2.3 规则三作用域要清楚尽量避免“跨块复用同名”let/const都是块级作用域block scope。同一个块里避免反复声明、避免在不同层级用同名变量会让读者在脑内“跳转”。反例同名遮蔽踩坑常见letkeywordVue;if(search){letkeywordsearch;// 遮蔽了外层 keyword后续你可能以为 keyword 一直是同一个}正例用更明确的变量名letkeywordVue;if(search){keywordsearch;}⬆ 返回目录2.4 变量命名你会在 Vue 里反复用到下面是我建议的“能直接用”的命名习惯普通值camelCase语义清晰例如userName、totalPrice布尔值优先加语义前缀is/has/can/should例如isLoading、hasMore数组复数名items、users、products事件/回调onXxx例如onSubmit、onClose临时变量尽量短但别乱缩写例如tmp可以但别变成t、x1这种不可读⬆ 返回目录三、函数写法优先“清晰 可复用”区分声明与箭头3.1 规则一函数做工具就写“函数声明”做回调就写“箭头函数”这不是绝对但能让团队形成一致的阅读节奏作为“可复用工具函数”文件顶部、export、util倾向function xxx(...) {}作为“回调”例如map/filter/watch里的一次性逻辑倾向const xxx () {}或内联箭头例子工具函数用声明functionformatMoney(cents){return(cents/100).toFixed(2);}例子回调用箭头consttotalitems.reduce((sum,item)sumitem.price,0);⬆ 返回目录3.2 规则二箭头函数逻辑简单就用隐式返回复杂就用大括号 显式 return简单表达式constisHot(p)p.score90;复杂逻辑constnormalizeProduct(p){constpricep.priceCents??0;return{...p,price};};这样做的好处是读者不用猜你的函数到底会不会做额外工作。⬆ 返回目录3.3 规则三参数处理清晰默认值优先避免“神秘 undefined”很多坑来自这种写法你在函数里不断判断x ...结果逻辑变得很难读。反例读者要脑内推导大量情况functioncalc(min,max){if(minmax)returnmax-min;if(min)returnmin;return0;}正例用默认值 明确语义functioncalc(min0,max0){if(max0)returnmax-min;returnmin;}⬆ 返回目录3.4 规则四尽量“早返回”减少深层嵌套Vue 写watch或处理筛选时最常见的代码风格问题就是深层if/else。反例嵌套过深functionfilterProducts(products,keyword){constres[];for(constpofproducts){if(keyword){if(p.name.includes(keyword)){res.push(p);}}else{res.push(p);}}returnres;}正例早返回逻辑更顺functionfilterProducts(products,keyword){if(!keyword)returnproducts;returnproducts.filter((p)p.name.includes(keyword));}⬆ 返回目录3.5 规则五纯函数优先副作用要“隔离”在 Vue 里计算数据computed尽量纯同样输入得到同样输出请求/日志/写状态这类副作用放到合适的地方actions、watch回调内部等纯函数示例functioncalcCartTotal(items){returnitems.reduce((sum,it)sumit.quantity*it.price,0);}副作用示例asyncfunctionloadProducts(api){constresawaitapi.getProducts();// 这里才开始处理“请求结果到状态”的逻辑returnres;}⬆ 返回目录四、TS 类型标注标注边界能推断就推断别滥用anyTS 的核心目标不是“把代码变长”而是让你在最该出错的地方更早发现问题。所以类型标注要遵循一个非常实用的策略规则总纲在“边界处”标注类型在“内部”尽量让 TS 推断。边界通常是函数参数 / 返回值尤其是对外暴露的函数API 请求数据的入口对象结构很复杂、很容易写错的地方4.1 规则一不要到处写类型优先让 TS 推断简单情况反例冗长但没带来额外安全constkeyword:stringVue;constpage:number1;正例短且不牺牲安全constkeywordVue;constpage1;⬆ 返回目录4.2 规则二公开函数/工具函数建议给入参和返回值尤其是你写到 util、通用函数、团队会复用的逻辑里。typeMoneyCentsnumber;functionformatMoney(cents:MoneyCents):string{return(cents/100).toFixed(2);}⬆ 返回目录4.3 规则三类型别写成“装饰品”要覆盖真实约束你要的是“约束”不是“占位”。例如 API 数据通常是最危险的边界。场景商品列表接口假设接口返回结构如下id必须存在且是字符串priceCents可能是数字tags可能为空我们在 TS 里可以这样建模typeProduct{id:string;name:string;priceCents:number;tags?:string[];};typeFilters{keyword?:string;minPriceCents?:number;maxPriceCents?:number;};如果你在后续筛选里把priceCents当成字符串用TS 就能在你写代码时提醒你。⬆ 返回目录4.4 规则四联合类型要配合“判别方式”或类型保护type guard反例看起来能编过但可能埋雷functiongetLabel(v:string|number){// 你没有区分类型就直接当字符串用returnv.toUpperCase();// number 没有 toUpperCase}正例判别联合 分支清晰functiongetLabel(v:string|number){if(typeofvstring)returnv.toUpperCase();returnString(v);}⬆ 返回目录4.5 规则五空值处理要“可读”优先??/ 可选链?.很多 Vue/TS 项目坑来自null/undefined混用。建议你在严格模式下保持习惯有默认值优先用??可能为 null优先用?.避免到处写强行断言asconstpriceCentsproduct.priceCents??0;constfirstTagproduct.tags?.[0]??;⬆ 返回目录4.6 规则六尽量少用类型断言as它只能当“最后一层保险”as可以让 TS 假装你说的是对的但如果你其实判断错了就会把运行时风险带回来。更推荐写“类型保护”functionisProduct(value:any):valueisProduct{return(valuetypeofvalue.idstringtypeofvalue.namestringtypeofvalue.priceCentsnumber);}⬆ 返回目录五、一套完整实战示例Vue 场景下的变量/函数/类型怎么选下面这个示例我会做成“你可以直接套进项目的写法”。场景商品列表页需要获取商品边界根据筛选条件计算展示列表纯函数优先格式化金额工具函数更新 UI 所需的数据状态层处理副作用5.1 TS 版本推荐写法简洁又规范typeProduct{id:string;name:string;priceCents:number;tags?:string[];};typeFilters{keyword?:string;minPriceCents?:number;maxPriceCents?:number;};functionformatMoney(cents:number):string{return(cents/100).toFixed(2);}functionmatchesFilters(p:Product,filters:Filters):boolean{constkeywordfilters.keyword??;constminPricefilters.minPriceCents??0;constmaxPricefilters.maxPriceCents??Number.POSITIVE_INFINITY;constbyKeywordkeyword?p.name.includes(keyword):true;constbyMinp.priceCentsminPrice;constbyMaxp.priceCentsmaxPrice;returnbyKeywordbyMinbyMax;}functionbuildDisplayList(products:Product[],filters:Filters){// 纯函数同样输入得到同样输出returnproducts.filter((p)matchesFilters(p,filters)).map((p)({id:p.id,title:p.name,priceText:formatMoney(p.priceCents),tags:p.tags??[],}));}你可以注意到这些“规范点”在一起工作时的效果变量默认用const只有需要重新赋值才用let此例基本不用let函数工具函数用声明回调用箭头逻辑清晰类型只在关键边界处建模Product/Filters内部让 TS 推断⬆ 返回目录5.2 反例同样的需求用 JS/TS 常见写法会怎么“变味”// 反例不建模滥用 any导致可读性和安全性都下降functionbuildDisplayList(products:any[],filters:any){constres[];for(constpofproducts){// p.priceCents 可能不是 number你没约束也没处理if(filters.keyword!p.name.includes(filters.keyword))continue;constpriceText(p.priceCents/100).toFixed(2);// 运行时才知道会不会炸res.push({id:p.id,title:p.name,priceText,tags:p.tags});}returnres;}这个反例会带来三个典型问题可读性any让读者无法判断结构是什么可维护性未来接口一变你不会在编译期得到提醒风险滞后错误往往到运行时才暴露⬆ 返回目录六、日常落地清单写完代码前你可以自检这 6 条你不需要背很多条只要养成“写完快速自检”的习惯这段代码里我有没有“随便用 let/var”而其实只需要const有无对象内部被我悄悄改了导致外部状态不可追踪函数是否逻辑被我写得很深有没有可以拆成纯函数/工具函数回调里我是否写成了“既做判断又做副作用”的大杂烩TS 里我有没有把关键边界参数/返回值用any或缺失类型导致约束失效null/undefined我有没有用清晰的??/?.处理有没有靠“运气”写断言⬆ 返回目录总结简洁不是随便规范是让你更快更稳const优先减少“变量会变”的认知成本让代码更稳定函数写法要遵循“清晰表达”工具函数清晰可复用回调函数紧凑好读TS 类型标注要守边界能推断就推断推断不了就在关键位置补上约束大多数线上坑不是你不会写而是你“写了但读不懂 / 约束没生效 / 风险滞后到运行时”⬆ 返回目录 系列模块导航 编码语法规范这是前端规范实战系列中第二个模块当编码语法规范模块更新完成之后会附上此模块的跳转链接方便同学们阅读学习。更新中敬请期待~ 跟着系列慢慢学把技术功底扎扎实实地打牢 系列总览「前端规范实战系列」正在持续更新中后续会整理一篇《前端规范实战系列全系列目录导航》包含每篇文章简介 直达链接方便大家按顺序、体系化学习。更新中敬请期待⬆ 返回目录技术成长从来不是比谁写得快而是比谁写得稳、规范、可维护。哪怕每次只吃透一条规范长期下来差距会非常明显。后续我会持续更新前端规范、工程化、可维护代码相关实战干货帮你告别面条代码、维护噩梦在开发与面试中更有底气。觉得有用欢迎点赞 收藏 关注不错过每一篇实战内容。我是 Eugene与你一起写规范、写优质代码我们下篇干货见