百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

2025 年每个 JavaScript 开发者都应该了解的功能

itomcoil 2025-08-06 20:29 1 浏览

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。

1.Iterator helpers

开发者经常会对同一个数组执行多次链式转换,例如:

const arr = [];
arr
  .slice(10, 20)
  .filter((el) => el < 10)
  .map((el) => el + 5);

这种方式非常低效,因为每次转换都需要分配一个新数组。JS 引入了迭代器方法,其工作原理与常规数组转换类似。不同之处在于其不会创建临时数组,而是创建新的迭代器,这些迭代器会在其他迭代器上进行迭代。

  • Iterator.prototype.drop():返回一个新的 Iterator Helper 对象,该对象会跳过此迭代器开头指定数量的元素,其作用大致与常规数组的 Array.prototype.slice(n) 相同
  • Iterator.prototype.take():返回一个新的 Iterator Helper 对象,该对象从此迭代器的开头获取指定数量的元素,其作用与常规数组的 Array.prototype.slice(0, n) 相同
  • Iterator.prototype.some():类似于 Array.prototype.some(),其测试迭代器生成的元素是否至少有一个通过了所提供函数实现的测试元素
  • Iterator.prototype.every():类似于 Array.prototype.every(),其测试迭代器生成的所有元素是否都通过了开发者所提供函数的测试
  • Iterator.prototype.filter():类似于 Array.prototype.filter(),其返回一个基于筛选值的迭代器
  • Iterator.prototype.find():类似于 Array.prototype.find(),其返回迭代器生成的第一个满足所提供测试函数的元素,否则返回 undefined
function* fibonacci() {
  let current = 1;
  let next = 1;
  while (true) {
    yield current;
    [current, next] = [next, current + next];
  }
}
const isEven = (x) => x % 2 === 0;
console.log(fibonacci().find(isEven));
// 输出 2
const isNegative = (x) => x < 0;
console.log(fibonacci().take(10).find(isNegative));
// undefined
console.log(fibonacci().find(isNegative));
// Never completes
  • Iterator.prototype.flatMap():类似于 Array.prototype.flatMap(),其返回一个基于扁平化值的迭代器
// 展平可迭代对象
const map1 = new Map([
  ["a", 1],
  ["b", 2],
  ["c", 3],
]);
const map2 = new Map([
  ["d", 4],
  ["e", 5],
  ["f", 6],
]);
const merged = new Map([map1, map2].values().flatMap((x) => x));
console.log(merged.get("a"));
// 1
console.log(merged.get("e"));
// 5

该方法可以避免创建任何 map 内容的临时副本。但需要注意的是,数组 [map1, map2] 必须先通过. values() 转换为迭代器,因为 Array.prototype.flatMap() 只能展平数组,而不能展平可迭代对象。

  • Iterator.prototype.forEach():类似于 Array.prototype.forEach(),其对迭代器生成的每个元素执行一次提供的函数
  • Iterator.prototype.map():类似于 Array.prototype.map(),其返回一个由映射函数转换后的值的迭代器
  • Iterator.prototype.reduce():类似于 Array.prototype.reduce(),其对迭代器生成的每个元素执行用户提供的 reducer 回调函数,并传入前一个元素计算的返回值
// 该示例创建迭代器,该迭代器产生斐波那契数列中的项,然后对前十个项求和
function* fibonacci() {
  let current = 1;
  let next = 1;
  while (true) {
    yield current;
    [current, next] = [next, current + next];
  }
}
console.log(
  fibonacci()
    .take(10)
    .reduce((a, b) => a + b),
);
// 输出 143
  • Iterator.prototype.toArray():使用填充的生成值创建一个数组

创建可迭代对象的常用方法是通过静态方法 Iterator.from() 以及 Array、NodeList、Set 和许多其他容器的 values() 方法。因此,上面转换链示例的更节省内存的版本是:

const arr = [];
arr
  .values()
  .drop(10)
  .take(10)
  .filter((el) => el < 10)
  .map((el) => el + 5)
  .toArray();

需要注意的是,这是一个相对较新的功能,最后一个开始支持此功能的主流浏览器是 Safari,其从 2025 年 3 月 31 日才开始支持。

2. 数组的 at() 方法

Array.prototype.at() 是访问第 n 个元素的另一种方法,其还支持负索引,即从最后一个元素开始计数。

例如,[10,20,30].at(-1) 将返回 30,[10,20,30].at(-2) 将返回 20 等等。这种负索引使得访问最后一个元素变得非常容易。在此之前,开发者则必须编写丑陋的样板代码 arr[arr.length - 1]。

3.Promise.withResolvers()

在异步调用场景,开发者经常会编写如下代码:

let resolve, reject;
const promise = new Promise((resolver, rejector) => {
  resolve = resolver;
  reject = rejector;
});
// 在特定场景下调用 resolve 或者 reject 方法

但是,借助于最新的 Promise.withResolvers(),开发者可以轻松实现同样的功能。

const {promise, resolve, reject} = Promise.withResolvers();

Promise.withResolvers() 静态方法返回一个对象,其中包含一个新的 Promise 对象和两个用于 resolve 或 reject 的函数,对应于传递给 Promise() 构造函数执行器的两个参数。

4.String.prototype.replace() / String.prototype.replaceAll() 回调

这是个老生常谈的问题,很多开发者不知道 String.prototype.replace() 或
String.prototype.replaceAll() 的第二个参数可以传入回调函数而不仅仅是字符串。例如:

let counter = 0;
console.log(
  "NUMBER, NUMBER, NUMBER".replaceAll(
    "NUMBER",
    (match) => match + "=" + ++counter
  )
); // NUMBER=1, NUMBER=2, NUMBER=3

replace() 和 replaceAll() 是一个非常强大的功能,其允许一次性完成多次替换。而且,从性能和内存角度来看都非常高效。

5. 交换变量的最新方法

很多开发者经常使用下面的方式来交换变量:

let a = 1,
  b = 2;
console.log(a, b);
// 当前输出 1, 2
const temp = a;
a = b;
b = temp;
console.log(a, b);
// 交换后的输出 2, 1

现在 JavaScript 引擎提供了更加简单的方式来实现同样的功能:

let a = 1,
  b = 2;
console.log(a, b);
// 交换前 1, 2
[a, b] = [b, a];
console.log(a, b);
// 交换后 2, 1

6. 结构化克隆 structuredClone()

大部分浏览器都已经支持 structuredClone() API,其可以深度复制大多数常规对象从而替换 JSON.stringify() 和 JSON.parse() 进行深度复制的功能。因为后者在很多场景可能并不符合预期:

  • JSON.stringify() 不支持某些值,例如: NaN 或 undefined,这些值会被跳过或转换为 null。同时,对于某些数据类型,例如: BigInt,该方法甚至会抛出异常。
  • JSON.stringify() 无法处理包含循环引用的对象:
const obj = {};
obj.selfReference = obj;
console.log(JSON.stringify(obj));
// 直接抛出异常
  • 对于较大的对象来说,该方法效率不高且浪费大量内存

因此总体来看,开发者应尽可能优先使用 structuredClone(),其还会循环引用对象。

const obj = {};
obj.selReference = obj;
const clonedObj = structuredClone(obj);
console.log(obj === clonedObj);
// 输出 false
console.log(clonedObj.selReference === clonedObj);
// 注意:输出 true

7.Tagged templates

大多数开发者都熟悉模板字面量 "`",但很多人并不知道标记模板,标记模板允许开发者使用函数解析模板字面量。标记函数的第一个参数包含一个字符串值数组,其余参数与表达式相关。当想对插值,甚至整个字符串,进行一些自动转换时,标记模板非常有用。

`string text`

`string text line 1
 string text line 2`

`string text ${expression} string text`

tagFunction`string text ${expression} string text`

例如,下面代码示例会在进行插值时自动转义 HTML 文本:

function escapeHtml(strings, ...arguments) {
  const div = document.createElement("div");
  let output = strings[0];
  for (let i = 0; i < arguments.length; ++i) {
    div.innerText = arguments[i];
    output += div.innerHTML;
    output += strings[i + 1];
  }
  return output;
}
console.log(escapeHtml`<br> ${"<br>"}`);
// 输出结果 <br> <br>

8.WeakMap / WeakSet

除了 Map 和 Set 之外,JavaScript 还支持 WeakMap 和 WeakSet。

WeakMap 和 WeakSet 与 Map 和 Set 类似,不同之处在于其不允许将原始值作为键,并且不提供迭代器。这样做的原因是,当指向某个键的所有引用丢失时,该键以及可能关联的值必须能够从 Map/Set 中释放并被垃圾回收。

const set = new WeakSet();
const map = new WeakMap();
{
  const key1 = new Date();
  const key2 = new Date();
  console.log(set.has(key1));
  // false
  set.add(key1);
  console.log(set.has(key1));
  // true
  console.log(map.get(key2));
  // undefined
  map.set(key2, 10);
  console.log(map.get(key2));
  // 10
}
// 注意:此处丢失了对 key1 和 key2 的引用,因此键和值会将被垃圾收集

因此,如果开发者希望将某事物与某个对象关联而不产生副作用,可以考虑使用 WeakMap 或 WeakSet。

9.Set 操作

最近,JavaScript 增加了对 Set 对象的布尔运算支持。

Set.prototype.difference()

集合差运算:

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);
console.log(set1.difference(set2));
// 输出 Set(2) {1, 2}

Set.prototype.intersection()

执行集合交运算:

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);
console.log(set1.intersection(set2));
// 输出 Set(2) {3, 4}

Set.prototype.union()

执行集合并操作:

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);
console.log(set1.union(set2));
// 输出 Set(6) {1, 2, 3, 4, 5, 6}

Set.prototype.symmetricDifference()

除去两个集合的公共元素:

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);
console.log(set1.symmetricDifference(set2));
// Set(4) {1, 2, 5, 6}

Set.prototype.isDisjointFrom()

返回一个布尔值,指示该集合与给定集合没有共同元素:

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);
const set3 = new Set([5, 6]);
console.log(set1.isDisjointFrom(set2));
// 输出 false
console.log(set1.isDisjointFrom(set3));
// 输出 true

Set.prototype.isSubsetOf()

返回一个布尔值,指示该集合的所有元素是否都在给定集合中:

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);
const set3 = new Set([5, 6]);
console.log(set1.isSubsetOf(set2));
// 输出 false
console.log(set3.isSubsetOf(set2));
// 输出  true

Set.prototype.isSupersetOf()

返回一个布尔值,指示给定集合的所有元素都在此集合中:

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);
const set3 = new Set([5, 6]);
console.log(set2.isSupersetOf(set1));
// 输出 false
console.log(set2.isSupersetOf(set3));
// 输出 true

参考资料

https://waspdev.com/articles

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/flatMap

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

https://medium.com/@emre.deniz/es2025-the-evolution-of-javascript-93d9f6fd5f5b

https://blog.bitsrc.io/javascript-iterables-vs-iterators-009162379a15?gi=7c4c7a926564

https://www.youtube.com/watch?v=8p9lPsui7Co

相关推荐

selenium(WEB自动化工具)

定义解释Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7,8,9,10,11),MozillaF...

开发利器丨如何使用ELK设计微服务中的日志收集方案?

【摘要】微服务各个组件的相关实践会涉及到工具,本文将会介绍微服务日常开发的一些利器,这些工具帮助我们构建更加健壮的微服务系统,并帮助排查解决微服务系统中的问题与性能瓶颈等。我们将重点介绍微服务架构中...

高并发系统设计:应对每秒数万QPS的架构策略

当面试官问及"如何应对每秒几万QPS(QueriesPerSecond)"时,大概率是想知道你对高并发系统设计的理解有多少。本文将深入探讨从基础设施到应用层面的解决方案。01、理解...

2025 年每个 JavaScript 开发者都应该了解的功能

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.Iteratorhelpers开发者...

JavaScript Array 对象

Array对象Array对象用于在变量中存储多个值:varcars=["Saab","Volvo","BMW"];第一个数组元素的索引值为0,第二个索引值为1,以此类推。更多有...

Gemini 2.5编程全球霸榜,谷歌重回AI王座,神秘模型曝光,奥特曼迎战

刚刚,Gemini2.5Pro编程登顶,6美元性价比碾压Claude3.7Sonnet。不仅如此,谷歌还暗藏着更强的编程模型Dragontail,这次是要彻底翻盘了。谷歌,彻底打了一场漂亮的翻...

动力节点最新JavaScript教程(高级篇),深入学习JavaScript

JavaScript是一种运行在浏览器中的解释型编程语言,它的解释器被称为JavaScript引擎,是浏览器的一部分,JavaScript广泛用于浏览器客户端编程,通常JavaScript脚本是通过嵌...

一文看懂Kiro,其 Spec工作流秒杀Cursor,可移植至Claude Code

当Cursor的“即兴编程”开始拖累项目质量,AWS新晋IDEKiro以Spec工作流打出“先规范后编码”的系统工程思维:需求-设计-任务三件套一次生成,文档与代码同步落地,复杂项目不...

「晚安·好梦」努力只能及格,拼命才能优秀

欢迎光临,浏览之前点击上面的音乐放松一下心情吧!喜欢的话给小编一个关注呀!Effortscanonlypass,anddesperatelycanbeexcellent.努力只能及格...

JavaScript 中 some 与 every 方法的区别是什么?

大家好,很高兴又见面了,我是姜茶的编程笔记,我们一起学习前端相关领域技术,共同进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力在JavaScript中,Array.protot...

10个高效的Python爬虫框架,你用过几个?

小型爬虫需求,requests库+bs4库就能解决;大型爬虫数据,尤其涉及异步抓取、内容管理及后续扩展等功能时,就需要用到爬虫框架了。下面介绍了10个爬虫框架,大家可以学习使用!1.Scrapysc...

12个高效的Python爬虫框架,你用过几个?

实现爬虫技术的编程环境有很多种,Java、Python、C++等都可以用来爬虫。但很多人选择Python来写爬虫,为什么呢?因为Python确实很适合做爬虫,丰富的第三方库十分强大,简单几行代码便可实...

pip3 install pyspider报错问题解决

运行如下命令报错:>>>pip3installpyspider观察上面的报错问题,需要安装pycurl。是到这个网址:http://www.lfd.uci.edu/~gohlke...

PySpider框架的使用

PysiderPysider是一个国人用Python编写的、带有强大的WebUI的网络爬虫系统,它支持多种数据库、任务监控、项目管理、结果查看、URL去重等强大的功能。安装pip3inst...

「机器学习」神经网络的激活函数、并通过python实现激活函数

神经网络的激活函数、并通过python实现whatis激活函数感知机的网络结构如下:左图中,偏置b没有被画出来,如果要表示出b,可以像右图那样做。用数学式来表示感知机:上面这个数学式子可以被改写:...