吆喝一声,如果你计算机、软件工程、电子等相关专业本科及以上学历,欢迎来共事。前后端/测试可投,技术大厂。
JavaScript 作为最流行的语言之一,其语法灵活且每年都在不断吸纳新特性,即使是一个从业多年的老手, 偶尔也会有一些被低估的 JavaScript 功能和技巧,本文将分享这些技巧,一同讨论探究。
1. 使用 flatMap
有些 JavaScript 方法尽管鲜为人知,但它们解决独特挑战的潜力能够增强编码效率, 比如
flatMap()
数组方法 flatMap()
本质上是 map()
和 flat()
的组合,区别在于 flatMap
只能扁平1级,flat 可以指定需要扁平的级数,flatmap 比分别调用这两个方法稍微高效一些。
使用 flat + map
使用 flatmap
flatmap 尽管是一个方法,但也会有 中间数组 (指中间创建了必须进行垃圾收集的临时数组)的产生,flatMap 非常适合在需要灵活性和可读性的情况下使用。
2. 充分使用 generator
生成器 (Generator) 和 迭代器 (iterators) 可能是 JavaScript 开发人员最不常使用的代码,其知识仅限于编码面试。(因为有更好用的语法糖 async/await
?😂)
生成器 (Generator) 是控制异步编程、生成可迭代对象和生成多个值的强大方法。生成器与传统函数不同。他们可以多次启动和停止执行。这使它们能够产生大量值并在以后继续执行,从而使它们非常适合管理异步操作、构造迭代器和处理无尽的数据流。
试想一下,假如在一个获取数据的场景下,数据库/ API 的数据量可能是无限的,而你必须将它们传输到前端,你会怎么做呢?
这种情况下, react 中最常用的方案就是无限加载方案, 如果是在 node 中或者原生JS,你该如何实现无限加载之类的功能。
3. console 的妙用
console 并不只有
console.log()
, 实际生产中都会使用已经封装好的log库,而 控制台对象 console 实际上内置了许多非常有用的方法,帮助您提高调试输出的质量和可读性,掌握它们能使您更轻松地 debug 和修复代码中的问题。
4. 深拷贝 structuredClone()
此前,如果开发人员想要深拷贝对象,经常需要依赖第三方库来实现或者手动实现一个神拷贝,或者采取 const cloneObj = JSON.parse(JSON.stringify(obj));
的 hack, 但其在处理包含循环引用或不符合 JSON 的数据类型(如 Map 和 Set,Blob 等 ) 的更复杂对象时,是有很多不足之处的
而现在,JavaScript 内置了一个 structuredClone() 的方法, 此方法提供了一种简单有效的方法来深度克隆对象, 且适用于大多数现代浏览器和 Node.js v17 以上
与众所周知的 JSON.parse(JSON.stringify())”
不同, structuredClone()
允许您克隆循环引用,这是目前在 JavaScript 中使用深拷贝最简单的方法。
5. 带标签的模板
带标签的模板(Tagged_Templates) - 是模板字符串(反引号)的一种更高级的形式,它允许你使用函数解析模板字面量。
这个高级特性我也是在 Next.js 14 发布后人们都在讨论的一张图才去了解的🫡,尽管这个特性是 ES6 就有的,至今已有8年!!!但我敢打赌知道这个并使用过这个特性的人屈指可数。
相信许多人已经见过下图(因为这个知识点请停止嘲笑 😝Next.js 14), 相信许多人的第一反应就是回到二十年前 PHP 时代并且代码容易遭受 sql 注入攻击 , 但实际上是安全的。这得益于模板字符串的高级特性 - ( 带标签的模板 -Tagged_Templates)
如果你不理解 Tagged_Templates 如何工作, 那么就让我用一个例子来简单说明下吧:
可以看到,Tagged Templates 的工作方式是将模板字符串里的所有字符串作为一个数组传递给函数的第一个参数,其余参数则根据相应的表达式直接插入到字符串中,Tagged Templates将 文字字符串 和表达式的结果 传递给函数,然后该函数可以以自定义方式操作并返回它们。这样开发者在构建 SQL 查询时,对输入进行适当的转义和验证,从而避免 SQL 注入攻击
。
带标签的模板字符串可用于很多用途,例如 安全性、i18n和本地化 等。
6. 空合并运算符 ??
空合并运算符 ?? (Nullish coalescing operator) 是一个逻辑运算符,当其左侧操作数为 null 或 undefined 时,它返回其右侧操作数,否则返回其左侧操作数
这有啥值得提的?||
不就行了 ?因为很多人在初学JS可能会困扰的一个问题是 假 (false) 和 假值(falsy) 的区别, 而 ??
和 ||
主要区别在于
??
仅当左操作数为 null 或 undefined 时,??
运算符才会将结果作为右操作数。||
运算符会将左操作数的所有假值(falsy) 的结果作为右操作数
举个例子:
JS的假值判断,可以参考这个表格 JavaScript-Equality-Table/:
7. 使用Symbols作为WeakMap的键
WeakMap
和 Map
很像,但不同点在于它的键(key) 只能是对象 Objects 和 symbol,这些键被作为弱引用存储(weakly)。
为什么?因为 WeakMap 的键必须是可垃圾回收的。大多数原始数据类型可以任意创建并且没有生命周期,因此它们不能用作键, 而 对象Objects 和 non-registered symbols 可以用作键,因为它们是垃圾可收集的 - MDN- WeakMap。
这个特性意味着除了键之外内存中没有其他对对象的引用,JavaScript 引擎可以在需要时对对象执行垃圾回收。
好了,那 WeakMap 到底有什么作用呢?根据其特点可以联想到 WeakMap 的用途可以是自定义缓存
以及检测内存泄漏
。
通过使用对象作为键,您可以将缓存的值与特定对象相关联。当对象被垃圾收集时,相应的 WeakMap 条目将被自动删除,立即清除缓存。
在 ES14 中, 使用 symbol 作为 WeakMap 的 key 已经成为可能, 这可以使键值对在 WeakMap 中扮演的角色更加清晰。因为唯一能在 WeakMap 中被作为 key 使用的原始类型只有 symbol, symbol 能保证 key 是 唯一的并且无法重新创建。
8. 函数式编程
自 2015 年以来,JavaScript 版本都会进行更新,今年(2023 ES14)也不例外。
ES14 最大的更新便是数组更新了许多数组方法或者为原有的数组方法增加不会带来突变(without mutation) 的互补方法。意味着它们会基于原数组创建新的数组,而不是直接修改原数组。
新增的互补方法有
Array.sort() -> Array.toSorted()
Array.splice() -> Array.toSpliced()
Array.reverse() -> Array.toReversed()
新增的新数组方法有:
Array with()
Array.findLast()
Array.findLastIndex()
今年的主题是更简单的函数式编程(fp) 和 不变性(immutability)。