javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript ECMAScript 2024功能

JavaScript新特性ECMAScript 2024(ES2024)核心功能的完整指南

作者:天天进步2015

JavaScript 作为 Web 开发的核心语言,每年都在不断演进,ECMAScript 2024(ES15)为开发者带来了一系列实用的新特性,本文将深入解析 ES2024 的核心新功能,并通过实际示例帮助你快速上手

引言

JavaScript 作为 Web 开发的核心语言,每年都在不断演进。ECMAScript 2024(ES15)为开发者带来了一系列实用的新特性,这些特性不仅提升了代码的可读性和简洁性,还增强了语言的表达能力。本文将深入解析 ES2024 的核心新功能,并通过实际示例帮助你快速上手。

1. Promise.withResolvers()

问题背景

在传统的 Promise 使用中,如果我们需要在外部控制 Promise 的状态,通常需要这样写:

let resolve, reject;
const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});

// 在其他地方调用
resolve('success');

这种模式虽然有效,但代码结构略显繁琐。

ES2024 解决方案

Promise.withResolvers() 方法提供了一种更优雅的方式来创建可外部控制的 Promise:

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

// 在需要的地方解决 Promise
setTimeout(() => {
  resolve('操作成功!');
}, 1000);

promise.then(result => console.log(result)); // 1秒后输出:操作成功!

实际应用场景

场景:实现一个可取消的请求队列

class RequestQueue {
  constructor() {
    this.queue = [];
  }

  enqueue(url) {
    const { promise, resolve, reject } = Promise.withResolvers();
    this.queue.push({ url, resolve, reject });
    return promise;
  }

  async processNext() {
    if (this.queue.length === 0) return;
    
    const { url, resolve, reject } = this.queue.shift();
    try {
      const response = await fetch(url);
      const data = await response.json();
      resolve(data);
    } catch (error) {
      reject(error);
    }
  }

  cancelAll() {
    this.queue.forEach(({ reject }) => {
      reject(new Error('请求已取消'));
    });
    this.queue = [];
  }
}

// 使用示例
const queue = new RequestQueue();
const request1 = queue.enqueue('/api/data1');
const request2 = queue.enqueue('/api/data2');

queue.processNext();
queue.processNext();

2. Object.groupBy() 和 Map.groupBy()

数据分组的常见需求

在处理数组数据时,我们经常需要根据某个属性对数据进行分组。以往通常使用 reduce 方法:

const users = [
  { name: '张三', role: 'admin' },
  { name: '李四', role: 'user' },
  { name: '王五', role: 'admin' }
];

// 传统方式
const grouped = users.reduce((acc, user) => {
  if (!acc[user.role]) acc[user.role] = [];
  acc[user.role].push(user);
  return acc;
}, {});

ES2024 新方法

Object.groupBy()

返回一个普通对象,键是分组的依据:

const usersByRole = Object.groupBy(users, user => user.role);
console.log(usersByRole);
// {
//   admin: [{ name: '张三', role: 'admin' }, { name: '王五', role: 'admin' }],
//   user: [{ name: '李四', role: 'user' }]
// }

Map.groupBy()

返回一个 Map 对象,适合使用非字符串作为键的场景:

const products = [
  { name: '笔记本', price: 5000 },
  { name: '鼠标', price: 100 },
  { name: '键盘', price: 300 },
  { name: '显示器', price: 2000 }
];

const priceRanges = Map.groupBy(products, product => {
  if (product.price < 500) return 'budget';
  if (product.price < 2000) return 'mid-range';
  return 'premium';
});

console.log(priceRanges.get('budget'));
// [{ name: '鼠标', price: 100 }, { name: '键盘', price: 300 }]

实际应用:数据分析仪表板

const salesData = [
  { date: '2024-01-15', amount: 1200, region: '华东' },
  { date: '2024-01-15', amount: 800, region: '华北' },
  { date: '2024-02-10', amount: 1500, region: '华东' },
  { date: '2024-02-10', amount: 900, region: '华北' }
];

// 按月份分组
const salesByMonth = Object.groupBy(salesData, sale => {
  return sale.date.substring(0, 7); // 获取 YYYY-MM
});

// 按地区和月份双重分组
const salesByRegion = Object.groupBy(salesData, sale => sale.region);
Object.keys(salesByRegion).forEach(region => {
  salesByRegion[region] = Object.groupBy(
    salesByRegion[region],
    sale => sale.date.substring(0, 7)
  );
});

console.log(salesByRegion);
// {
//   华东: {
//     '2024-01': [...],
//     '2024-02': [...]
//   },
//   华北: { ... }
// }

3. 正则表达式v标志

增强的 Unicode 支持

ES2024 引入了新的 v 标志,提供了比 u 标志更强大的 Unicode 属性支持。

集合操作

使用 v 标志,你可以在字符类中进行集合操作:

// 匹配所有字母但排除元音字母
const consonants = /[\p{Letter}--[aeiouAEIOU]]/v;
console.log(consonants.test('b')); // true
console.log(consonants.test('a')); // false

// 交集操作:匹配既是字母又是 ASCII 字符的字符
const asciiLetters = /[\p{Letter}&&\p{ASCII}]/v;
console.log(asciiLetters.test('a')); // true
console.log(asciiLetters.test('α')); // false (希腊字母)

// 联合操作
const lettersAndDigits = /[\p{Letter}\p{Number}]/v;

字符串属性

// 匹配表情符号
const emojiRegex = /\p{Emoji}/v;
console.log(emojiRegex.test('😊')); // true
console.log(emojiRegex.test('Hello')); // false

// 匹配特定脚本
const chineseOnly = /^\p{Script=Han}+$/v;
console.log(chineseOnly.test('你好')); // true
console.log(chineseOnly.test('你好World')); // false

实际应用:表单验证

// 用户名验证:只允许字母、数字和下划线,但不允许纯数字
function validateUsername(username) {
  // 使用减法运算排除纯数字情况
  const usernamePattern = /^[\p{Letter}\p{Number}_]{3,20}$/v;
  const notOnlyNumbers = /\p{Letter}/v;
  
  return usernamePattern.test(username) && notOnlyNumbers.test(username);
}

console.log(validateUsername('user123')); // true
console.log(validateUsername('123456')); // false
console.log(validateUsername('用户名123')); // true

// 密码强度检查:必须包含大小写字母、数字
function validatePassword(password) {
  const hasLower = /\p{Lowercase_Letter}/v;
  const hasUpper = /\p{Uppercase_Letter}/v;
  const hasDigit = /\p{Number}/v;
  
  return hasLower.test(password) && 
         hasUpper.test(password) && 
         hasDigit.test(password) &&
         password.length >= 8;
}

4. ArrayBuffer 和 SharedArrayBuffer 的改进

可调整大小的 ArrayBuffer

ES2024 允许创建可以动态调整大小的 ArrayBuffer:

// 创建一个最大容量为 1024 字节的可调整 ArrayBuffer
const buffer = new ArrayBuffer(512, { maxByteLength: 1024 });

console.log(buffer.byteLength); // 512
console.log(buffer.maxByteLength); // 1024
console.log(buffer.resizable); // true

// 调整大小
buffer.resize(768);
console.log(buffer.byteLength); // 768

// 尝试超出最大容量会抛出错误
// buffer.resize(2048); // RangeError

可增长的 SharedArrayBuffer

对于多线程场景,SharedArrayBuffer 也支持动态增长:

const shared = new SharedArrayBuffer(256, { maxByteLength: 512 });

console.log(shared.growable); // true

// 增长缓冲区
shared.grow(384);
console.log(shared.byteLength); // 384

实际应用:高性能数据流处理

class DynamicBuffer {
  constructor(initialSize = 1024, maxSize = 1024 * 1024) {
    this.buffer = new ArrayBuffer(initialSize, { maxByteLength: maxSize });
    this.view = new Uint8Array(this.buffer);
    this.position = 0;
  }

  write(data) {
    const needed = this.position + data.length;
    
    // 如果空间不足,自动扩容(翻倍策略)
    if (needed > this.buffer.byteLength) {
      const newSize = Math.min(
        Math.max(this.buffer.byteLength * 2, needed),
        this.buffer.maxByteLength
      );
      this.buffer.resize(newSize);
      this.view = new Uint8Array(this.buffer);
    }

    this.view.set(data, this.position);
    this.position += data.length;
  }

  getData() {
    return this.view.slice(0, this.position);
  }
}

// 使用示例
const buffer = new DynamicBuffer();
buffer.write(new Uint8Array([1, 2, 3]));
buffer.write(new Uint8Array([4, 5, 6, 7, 8]));
console.log(buffer.getData()); // Uint8Array(8) [1, 2, 3, 4, 5, 6, 7, 8]

5. 其他值得关注的特性

Atomics.waitAsync()

对于 Web Workers 和共享内存场景,Atomics.waitAsync() 提供了非阻塞的等待机制:

// 主线程
const sab = new SharedArrayBuffer(4);
const view = new Int32Array(sab);

Atomics.waitAsync(view, 0, 0).value.then(result => {
  console.log('值已更改!', result); // { async: true, value: 'ok' }
});

// 在 Worker 中
// Atomics.store(view, 0, 123);
// Atomics.notify(view, 0);

Array.prototype.findLast() 和 findLastIndex()

虽然这些方法在 ES2023 引入,但值得一提:

const numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];

// 从后往前查找第一个偶数
const lastEven = numbers.findLast(n => n % 2 === 0);
console.log(lastEven); // 2

const lastEvenIndex = numbers.findLastIndex(n => n % 2 === 0);
console.log(lastEvenIndex); // 7

浏览器兼容性

在使用这些新特性之前,请检查目标浏览器的支持情况:

对于不支持的浏览器,可以使用 Babel 和相应的 polyfills。

实战项目:数据分析工具

让我们结合这些新特性构建一个简单的数据分析工具:

class DataAnalyzer {
  constructor() {
    this.data = [];
    const { promise, resolve } = Promise.withResolvers();
    this.readyPromise = promise;
    this.markReady = resolve;
  }

  async loadData(url) {
    try {
      const response = await fetch(url);
      this.data = await response.json();
      this.markReady();
    } catch (error) {
      console.error('加载数据失败:', error);
    }
  }

  async groupByCategory() {
    await this.readyPromise;
    return Object.groupBy(this.data, item => item.category);
  }

  async groupByPriceRange() {
    await this.readyPromise;
    return Map.groupBy(this.data, item => {
      if (item.price < 100) return 'low';
      if (item.price < 500) return 'medium';
      return 'high';
    });
  }

  async filterByPattern(pattern) {
    await this.readyPromise;
    const regex = new RegExp(pattern, 'v');
    return this.data.filter(item => regex.test(item.name));
  }
}

// 使用示例
const analyzer = new DataAnalyzer();
analyzer.loadData('/api/products');

analyzer.groupByCategory().then(groups => {
  console.log('按类别分组:', groups);
});

analyzer.groupByPriceRange().then(ranges => {
  console.log('低价产品:', ranges.get('low'));
});

总结

ES2024 带来的新特性虽然不多,但每一个都解决了实际开发中的痛点:

这些特性不仅提高了代码的可读性和开发效率,也为构建更复杂的应用提供了基础。建议在新项目中积极采用这些特性,同时也要注意浏览器兼容性问题。

随着 JavaScript 生态的不断成熟,我们可以期待未来更多激动人心的新特性。保持学习,拥抱变化,让我们一起编写更优雅的现代 JavaScript 代码!

到此这篇关于JavaScript新特性ECMAScript 2024(ES2024)核心功能的完整指南的文章就介绍到这了,更多相关JavaScript ECMAScript 2024功能内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文