广州总部电话:020-85564311
广州总部电话:020-85564311

广州网站建设-小程序商城开发-广州小程序开发-企业微信开发公司-网站建设高端品牌-优网科技

20年
互联网应用服务商
请输入搜索关键词
知识库 知识库

优网知识库

探索行业前沿,共享知识宝库

2025 年每个 JavaScript 开发者都应该了解的功能
发布日期:2025-04-25 20:14:08 浏览次数: 817 来源:前端技术进阶

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

1.Iterator helpers

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

const arr = [];
arr
  .slice(1020)
  .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
functionfibonacci({
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 回调函数,并传入前一个元素计算的返回值
// 该示例创建迭代器,该迭代器产生斐波那契数列中的项,然后对前十个项求和
functionfibonacci({
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 = newPromise((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 引擎提供了更加简单的方式来实现同样的功能:

leta=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 文本:

functionescapeHtml(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 中释放并被垃圾回收。

constset = new WeakSet();
constmap = 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 = newSet([1234]);
const set2 = newSet([3456]);
console.log(set1.difference(set2));
// 输出 Set(2) {1, 2}

Set.prototype.intersection()

执行集合交运算:

const set1 = newSet([1234]);
const set2 = newSet([3456]);
console.log(set1.intersection(set2));
// 输出 Set(2) {3, 4}

Set.prototype.union()

执行集合并操作:

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

Set.prototype.symmetricDifference()

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

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

Set.prototype.isDisjointFrom()

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

const set1 = newSet([1234]);
const set2 = newSet([3456]);
const set3 = newSet([56]);
console.log(set1.isDisjointFrom(set2));
// 输出 false
console.log(set1.isDisjointFrom(set3));
// 输出 true

Set.prototype.isSubsetOf()

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

const set1 = newSet([1234]);
const set2 = newSet([3456]);
const set3 = newSet([56]);
console.log(set1.isSubsetOf(set2));
// 输出 false
console.log(set3.isSubsetOf(set2));
// 输出  true

Set.prototype.isSupersetOf()

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

const set1 = newSet([1234]);
const set2 = newSet([3456]);
const set3 = newSet([56]);
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


优网科技,优秀企业首选的互联网供应服务商

优网科技秉承"专业团队、品质服务" 的经营理念,诚信务实的服务了近万家客户,成为众多世界500强、集团和上市公司的长期合作伙伴!

优网科技成立于2001年,擅长网站建设、网站与各类业务系统深度整合,致力于提供完善的企业互联网解决方案。优网科技提供PC端网站建设(品牌展示型、官方门户型、营销商务型、电子商务型、信息门户型、DIY体验、720全景展厅及3D虚拟仿真)、移动端应用(手机站APP开发)、微信定制开发(微信官网、微信商城、企业微信)、微信小程序定制开发等一系列互联网应用服务。


我要投稿

姓名

文章链接

提交即表示你已阅读并同意《个人信息保护声明》

专属顾问 专属顾问
扫码咨询您的优网专属顾问!
专属顾问
马上咨询
联系专属顾问
联系专属顾问
联系专属顾问
扫一扫马上咨询
扫一扫马上咨询

扫一扫马上咨询

和我们在线交谈!