25个你一定要掌握的JavaScript技巧,是新手到高手的进阶秘籍!

发布时间:2026/10/6 3:23:32

25个你一定要掌握的JavaScript技巧,是新手到高手的进阶秘籍! JavaScript 一直在更新变得越来越好用。从 ES6 开始加入了很多新写法能让你的代码更短、更清楚也常常运行得更快。掌握这些技巧不仅能让你写代码更快还能让代码更容易让别人看懂和维护代码质量也更好。下面直接介绍 25 个现代 JavaScript 中很实用的技巧和写法学会它们写代码真的会轻松很多1. 三元运算符一行搞定简单判断用 ? : 代替简单的 if/else代码更紧凑。// 老方法let age 18;let canVote;if (age 18) {canVote Yes;} else {canVote No;}console.log(canVote);//输出: Yes//新方法 (三元运算符)let age 18;let canVote (age 18) ? Yes : No;//一行搞定console.log(canVote);//输出: Yes2. || 设置默认值防 undefined/null如果变量可能是 null、undefined、0、 或 false用 || 给它一个后备值。// 老方法 (检查空值)functiongreet(name) {let displayName;if (name null || name undefined || name ) {displayName Guest;} else {displayName name;}console.log(Hello, ${displayName}!);}//新方法 (|| 短路)functiongreet(name) {const displayName name || Guest;// name为假值就用 Guestconsole.log(Hello, ${displayName}!);}greet(Alice);// Hello, Alice!greet(null);// Hello, Guest!greet();// Hello, Guest! (注意空字符串也被认为是假值)3. 条件执行满足条件才做事用 只在条件为真时才执行后面的代码适合简单的操作。// 老方法let isAdmin true;if (isAdmin) {console.log(Admin privileges granted.);}//新方法 ( 短路)let isAdmin true;isAdmin console.log(Admin privileges granted.);//输出: Admin privileges granted.let isGuest false;isGuest console.log(Guest access.);//没输出因为 isGuest 是 false4. 模板字符串拼接变量超方便用反引号 包裹字符串里面用 ${变量} 插入变量或表达式告别一堆加号。// 老方法 (加号拼接)const name Bob;const age 30;console.log(My name is name and I am age years old.);//新方法 (模板字符串)const name Bob;const age 30;console.log(My name is ${name} and I am ${age} years old.);//输出: My name is Bob and I am 30 years old.5. 箭头函数写函数更简短写法 (参数) 表达式 比 function 短尤其适合做回调。注意箭头函数没有自己的 this它会用外面函数的 this。// 老方法const numbers [1, 2, 3];const doubled numbers.map(function(num) {return num * 2;});//新方法 (箭头函数)const numbers [1, 2, 3];const doubled numbers.map(num num * 2);//一行自动返回结果console.log(doubled);//输出: [2, 4, 6]// this的区别 (重要)functionTimer() {this.seconds 0;//普通函数里面的 this 可能指向 window 或 undefined (严格模式)setInterval(function() {// console.log(this.seconds); //错误this 不对}, 1000);//箭头函数里面的 this 就是 Timer 实例的 thissetInterval(() {this.seconds;console.log(this.seconds);//正确每秒1}, 1000);}const myTimer new Timer();6. 解构数组快速取元素直接从数组里把值提取到变量里还能跳过某些元素。// 老方法const colors [red, green, blue];const firstColor colors[0];const secondColor colors[1];//新方法 (数组解构)const colors [red, green, blue];const [firstColor, secondColor] colors;//按顺序提取console.log(firstColor, secondColor);//输出: red greenconst [,, thirdColor] colors;//跳过前两个console.log(thirdColor);//输出: blue7. 解构对象快速取属性直接从对象里把属性值提取到变量里还能给属性换名字。// 老方法const user { name: Charlie, age: 25, city: NYC };const userName user.name;const userAge user.age;//新方法 (对象解构)const user { name: Charlie, age: 25, city: NYC };const { name, age } user;//提取 name 和 ageconsole.log(name, age);//输出: Charlie 25const { name: fullName, city } user;//把 name 提取到 fullName 变量console.log(fullName, city);//输出: Charlie NYC8. ... 展开数组复制和合并用 ... 轻松复制数组或把多个数组合成一个新数组。// 老方法const arr1 [1, 2];const arr2 [3, 4];const copiedArr arr1.slice();//复制const combinedArr arr1.concat(arr2);//合并//新方法 (展开语法 ...)const arr1 [1, 2];const arr2 [3, 4];const copiedArr [...arr1];//复制 arr1const combinedArr [...arr1, ...arr2];//合并 arr1 和 arr2console.log(copiedArr, combinedArr);//输出: [1, 2] [1, 2, 3, 4]9. ... 展开对象复制和合并用 ... 轻松复制对象或把多个对象属性合并到一个新对象里。后面的属性会覆盖前面的同名属性。// 老方法const obj1 { a: 1, b: 2 };const obj2 { c: 3, d: 4 };const copiedObj Object.assign({}, obj1);//复制const mergedObj Object.assign({}, obj1, obj2);//合并//新方法 (展开语法 ...)const obj1 { a: 1, b: 2 };const obj2 { c: 3, d: 4 };const copiedObj { ...obj1 };//复制 obj1const mergedObj { ...obj1, ...obj2 };//合并 obj1 和 obj2console.log(copiedObj, mergedObj);//输出: {a:1, b:2} {a:1, b:2, c:3, d:4}//覆盖属性const original { x: 1, y: 2 };const updated { ...original, y: 3, z: 4 };//覆盖 y, 添加 zconsole.log(updated);//输出: {x:1, y:3, z:4}10. ... 剩余参数收集多个参数函数定义时用 ...参数名可以把传进来的多个参数自动收集到一个数组里。// 老方法 (用 arguments)functionsumAll() {let total 0;for (let i 0; i arguments.length; i) {total arguments[i];}return total;}//新方法 (剩余参数 ...)functionsumAll(...numbers) {// numbers是个数组return numbers.reduce((total, num) total num, 0);//用 reduce 求和}console.log(sumAll(1, 2, 3, 4));//输出: 1011. 默认参数参数没传就用默认值直接在函数参数后面用 默认值如果调用时没传这个参数或者传了 undefined就用默认值。// 老方法 (用 ||)functiongreet(name, greeting) {name name || Guest;greeting greeting || Hello;console.log(${greeting}, ${name}!);}//新方法 (默认参数)functiongreet(name Guest, greeting Hello) {console.log(${greeting}, ${name}!);}greet();//输出: Hello, Guest! (两个都用默认值)greet(Frank);//输出: Hello, Frank! (greeting 用默认值)greet(Grace, Hi);//输出: Hi, Grace! (都不用默认值)12. ?. 可选链安全访问深层属性用 ?. 访问可能不存在的对象属性(null 或 undefined)避免代码报错崩掉返回 undefined。// 老方法 (层层检查)const user {profile: {address: {street: Main St}}};let streetName;if (user user.profile user.profile.address) {streetName user.profile.address.street;}console.log(streetName);//输出: Main Stconst invalidUser {};//没有 profilelet invalidStreet;//下面如果直接访问 invalidUser.profile.address 会报错!if (invalidUser invalidUser.profile invalidUser.profile.address) {invalidStreet invalidUser.profile.address.street;//不会执行到这里}console.log(invalidStreet);//输出: undefined//新方法 (可选链 ?.)const streetName user.profile?.address?.street;//安全访问console.log(streetName);//输出: Main Stconst invalidStreet invalidUser.profile?.address?.street;//遇到 null/undefined 就停返回 undefinedconsole.log(invalidStreet);//输出: undefined13. ?? 空值合并只关心 null/undefined用 ?? 判断只有左边是 null 或 undefined 时才用右边的默认值。和 || 不同0、、false 这些有效值不会被覆盖。// || 的问题 (会把 0, , false 也当成无效值)const count 0;const defaultCount_OR count || 10;// 0是假值所以用了 10console.log(defaultCount_OR);//输出: 10 (但 0 可能是有效值)// ??正确解决const count 0;const defaultCount_NC count ?? 10;// 0不是 null/undefined保留 0console.log(defaultCount_NC);//输出: 0const emptyString ;const defaultString_NC emptyString ?? Default;// 不是 null/undefined保留 console.log(defaultString_NC);//输出: const undefinedValue undefined;const defaultValue_NC undefinedValue ?? Fallback;// undefined是 nullish用 Fallbackconsole.log(defaultValue_NC);//输出: Fallback14. forEach遍历数组每个元素比 for 循环更简洁地遍历数组对每个元素做点事情。// 老方法 (for 循环)const items [apple, banana, cherry];for (let i 0; i items.length; i) {console.log(items[i]);}//新方法 (forEach)const items [apple, banana, cherry];items.forEach(item console.log(item));//对每个 item 执行 console.log//输出:// apple// banana// cherry15. map把数组变形成新数组遍历原数组对每个元素进行转换把所有转换结果放入一个新数组返回。// 老方法 (for 循环 push)const numbers [1, 2, 3];const squaredNumbers [];for (let i 0; i numbers.length; i) {squaredNumbers.push(numbers[i] * numbers[i]);}//新方法 (map)const numbers [1, 2, 3];const squaredNumbers numbers.map(num num * num);//计算平方console.log(squaredNumbers);//输出: [1, 4, 9]16. filter按条件筛选数组元素遍历原数组只把满足条件的元素放入一个新数组返回。//老方法(for循环ifpush)constages [10, 20, 15, 30];constadults [];for(leti0;iages.length;i) {if(ages[i] 18) {adults.push(ages[i]);}}//新方法(filter)constages [10, 20, 15, 30];constadultsages.filter(ageage18);//只保留18的console.log(adults);//输出: [20, 30]17. reduce把数组“压缩”成一个值遍历数组把元素逐个和一个“累加器”进行计算(比如累加、拼接、找最大值)最终得到一个结果值。功能很强大。// 老方法 (for 循环求和)const prices [10, 20, 5];let totalPrice 0;for (let i 0; i prices.length; i) {totalPrice prices[i];}//新方法 (reduce 求和)const prices [10, 20, 5];const totalPrice prices.reduce((sum, price) sum price, 0);//从0开始累加console.log(totalPrice);//输出: 35//复杂例子: 拍平数组 (把二维数组变一维)const nestedArrays [[1, 2], [3, 4], [5]];const flattened nestedArrays.reduce((acc, currentArray) [...acc, ...currentArray],//把当前数组展开拼接到累加器后面[]//初始累加器是空数组);console.log(flattened);//输出: [1, 2, 3, 4, 5]18. Object.keys/values/entries操作对象属性方便地获取对象的键、值或者键值对数组用来遍历对象。const car {make: Toyota,model: Camry,year: 2020};//获取所有属性名 (keys)console.log(Object.keys(car));//输出: [make, model, year]//获取所有属性值 (values)console.log(Object.values(car));//输出: [Toyota, Camry, 2020]//获取键值对数组 (entries) - 每个元素是 [key, value]console.log(Object.entries(car));/*输出:[[make, Toyota],[model, Camry],[year, 2020]]*///用 entries 遍历对象Object.entries(car).forEach(([key, value]) {console.log(${key}: ${value});});/*输出:make: Toyotamodel: Camryyear: 2020*/19. 箭头函数隐式返回省略 return当箭头函数只有一行表达式时可以省略 {} 和 return 关键字直接写表达式它会自动返回这个表达式的结果。注意返回对象字面量时需要用小括号 () 包裹对象 {}。// 显式返回const add (a, b) {return a b;};//隐式返回 (一行表达式)const add (a, b) a b;//自动返回 a b 的结果console.log(add(5, 3));//输出: 8//隐式返回对象 (必须加括号)const createUser (name, age) ({ name, age });//返回 {name: name, age: age}console.log(createUser(Dora, 28));//输出: { name: Dora, age: 28 }20. !! 转布尔值快速判断真假用两个感叹号 !! 可以把任何类型的值快速转换成真正的布尔值 (true 或 false)。第一个 ! 把值转成布尔值再取反第二个 ! 再取反一次就得到原值的真实布尔等价。// 老方法 (if 判断赋值)const value hello;let isTruthy;if (value) {isTruthy true;} else {isTruthy false;}//新方法 (!! 转换)const value1 hello;const isTruthy1 !!value1;// !!hello - trueconsole.log(isTruthy1);//输出: trueconst value2 0;const isTruthy2 !!value2;// !!0 - falseconsole.log(isTruthy2);//输出: falseconst value3 null;const isTruthy3 !!value3;// !!null - falseconsole.log(isTruthy3);//输出: false21. 转数字字符串变数字最快方法在表示数字的字符串前面加一个 号能快速把它转换成真正的数字类型。// 老方法 (parseInt/parseFloat)const numStr 123;const num parseInt(numStr, 10);//新方法 ( 转换)const numStr 123;const num numStr;//字符串转整数console.log(num, typeof num);//输出: 123 numberconst floatStr 123.45;const floatNum floatStr;//字符串转浮点数console.log(floatNum, typeof floatNum);//输出: 123.45 number22. 属性简写变量名即属性名当对象的属性名和要赋值的变量名完全一样时可以只写变量名省略冒号和值。// 老方法const firstName John;const lastName Doe;const age 40;const user {firstName: firstName,//属性名: 变量名lastName: lastName,age: age};//新方法 (属性简写)const firstName John;const lastName Doe;const age 40;const user {firstName,//等同于 firstName: firstNamelastName,//等同于 lastName: lastNameage//等同于 age: age};console.log(user);//输出: { firstName: John, lastName: Doe, age: 40 }23. for...of 循环直接遍历值直接遍历数组、字符串等可迭代对象里的值不需要操作索引 i。// 老方法 (for 循环遍历值)const fruits [apple, banana, orange];for (let i 0; i fruits.length; i) {console.log(fruits[i]);}//新方法 (for...of)const fruits [apple, banana, orange];for (const fruit of fruits) {// fruit直接是数组元素console.log(fruit);}/*输出:applebananaorange*///遍历字符串for (constchar of hello) {console.log(char);}/*输出:hello*/24. 交换变量不用临时变量用数组解构一行代码直接交换两个变量的值。// 老方法 (需要 temp 变量)let a 1;let b 2;let temp a;a b;b temp;//新方法 (解构交换)let a 1;let b 2;[a, b] [b, a];//右边创建 [2, 1], 左边解构赋值给 a, bconsole.log(a, b);//输出: 2 125. console.table()表格打印数据调试神器把对象数组或者对象本身在浏览器控制台里用清晰的表格打印出来一目了然。constusers [{ id:1, name:Alice, age:28 },{ id:2, name:Bob, age:35 },{ id:3, name:Charlie, age:22 }];console.table(users);/*浏览器控制台输出类似表格:(index)|id|name|age--------|----|---------|----0|1|Alice|281|2|Bob|352|3|Charlie|22*/constperson {firstName:Jane,lastName:Doe,occupation:Developer};console.table(person);/*浏览器控制台输出类似表格:(index)|Value-----------|-----------firstName|JanelastName|Doeoccupation|Developer*/写在最后这 25 个 JavaScript 技巧都是现代开发中天天能用上的好东西。学会它们能实实在在地帮你省下敲代码的时间让代码看起来更整洁写起来也更顺手。它们代表了 JavaScript 高效编程的核心方法。
延伸阅读

更多相关文章

2026/10/6 3:18:31

旧电脑改造NAS全攻略:硬件选型到数据备份的实战指南

家里那台旧电脑吃灰半年后,我总算给它找了个正经归宿——自建一台家用NAS。折腾下来最大的感受是:网上教程多,但能一口气把事情讲透的太少。要么只给你甩几条命令,要么上来就推高价成品机,很少有人把“为什么要这样选”…

2026/10/6 3:18:31

黑马点评缓存一致性治理:基于Cache Aside模式的可靠落地

黑马点评这个项目,很多人做完之后都有一个共同感受:功能都通了,但自己写的缓存代码到底靠不靠谱,心里完全没底。商户查询加了 Redis,照着视频写了缓存查询和更新逻辑,跑起来也很快,可一旦被人问…

2026/10/6 3:18:31

华为交换机VLAN间通信实战:Trunk+单臂路由配置与排错

两台交换机之间拉一根线,跑 Trunk,把 VLAN 100 和 200 放过去;PC 接交换机走 Access,老老实实划进自己的 VLAN;最后再由一台路由器把两个 VLAN 的网关终结掉。这个组网如果你配过华为设备,应该一眼就能认出…

2026/10/6 4:33:35

深入理解 .NET 任务并行库 ContinueWhenAll:多任务合流与延续机制

搞异步编程这么多年,我一直在跟 .NET 的任务并行库(TPL)打交道。最初接触 TPL 的时候,处理并行任务之间的先后顺序最让我头疼,尤其是“一批任务全部跑完,再做下一件事”这种常见的场景。当时我用得最多的就…

2026/10/6 4:33:35

在线课堂微信小程序毕设实战:Spring Boot全栈管理系统设计与实现

最近被问爆的一个毕业设计选题:“基于微信小程序实现在线课堂微信小程序管理系统【附项目源码论文说明】”。这个标题几乎是每年毕设季的常客——它既不是纯前端页面堆砌,也不是一个后端接口集合,而是一套真正有业务闭环的完整系统&#xff1…

2026/10/6 4:33:35

停车场模拟课设详解:栈和队列如何实现后进先出与先进先出

简介:一份关于停车场模拟管理系统的课程设计报告,从线性表逻辑与存储结构角度完整呈现系统设计与实现过程。报告包含设计目的、数据结构设计、功能模块划分(车辆进入、离开、状态查询)、界面设计、运行测试及排错思路,…

2026/10/6 4:33:35

系统盘制作完全指南:从U盘启动盘到UEFI/Legacy避坑

如果你装过系统,大概率经历过这样的场景:朋友抱着一台笔记本问你“系统坏了能不能帮我重装一下”,你满口答应,结果翻遍抽屉只找到一枚不知道哪年的旧U盘。那一刻你才意识到,平时刻一个系统启动盘是多么不该偷懒的事。“…

2026/10/6 4:33:35

Superpowers:LLM嵌入式认知协作者的架构与实战

1. 项目概述:Superpowers 不是超能力,而是开发者工具链的“认知增强层”最近在多个技术社区和开发者群聊里,“superpowers”这个词出现频率陡增——它既不是漫威新电影的彩蛋,也不是某款玄幻手游的更新公告,而是一个真…

2026/10/6 4:28:35

superpowers:AI编程环境的范式迁移与身份驱动架构

1. “superpowers”不是功能开关,而是开发者工作流的范式迁移最近在多个技术社区和开发工具讨论区里,“superpowers”这个词出现频率高得反常——它既不指向某个具体开源项目,也不属于任何主流框架的官方术语,却频繁出现在 Cursor…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/6 4:01:51

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/5 17:38:27

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 0:03:23

MR25H40CDF+STM32F031C6工业级高可靠数据存储方案

1. 项目概述:为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储?在工厂产线的 PLC 控制柜里、在风电变流器的散热片背面、在矿井监测终端的金属外壳下,你经常能看到一块指甲盖大小的黑色芯片——它既不是 Flash,也不是…

2026/10/6 0:03:23

MRAM+STM32工业断电数据保全实战指南

1. 项目概述:为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储?在工厂产线的PLC柜里、在野外无人值守的环境监测终端里、在高速运转的包装机控制板上,你经常能看到一块指甲盖大小的黑色芯片,旁边贴着“MR25H40CDF”丝…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑