ES2015 (ES6) - 基础特性
ES2015 是 JavaScript 历史上最重要的版本更新,引入了现代 JavaScript 的核心概念,彻底改变了 JavaScript 的编程范式。
它奠定了现代前端开发的基础,是从传统 JavaScript 向现代 JavaScript 转变的分水岭。
1. let 和 const
let:块级作用域变量声明,避免变量提升和重复声明。 const:声明常量,赋值后不可更改。
// let 示例
let x = 1;
{
let x = 2; // 不同的块级作用域
console.log(x); // 2
}
console.log(x); // 1
// const 示例
const PI = 3.14159;
const obj = { name: 'John' };
obj.name = 'Jane'; // 可以修改对象属性
// obj = {}; // 错误:不能重新赋值
2. 箭头函数 (Arrow Functions)
简洁的函数写法,自动绑定外部 this。
// 基本语法
const add = (a, b) => a + b;
// 多行函数体
const multiply = (a, b) => {
const result = a * b;
return result;
};
// this 绑定示例
class Counter {
constructor() {
this.count = 0;
}
start() {
setInterval(() => {
this.count++; // this 正确绑定到 Counter 实例
console.log(this.count);
}, 1000);
}
}
3. 模板字符串 (Template Literals)
使用反引号 ``,支持多行和变量插值。
// 基本插值
const name = 'World';
const greeting = `Hello ${name}!`;
// 多行字符串
const html = `
<div>
<h1>${title}</h1>
<p>${content}</p>
</div>
`;
// 标签模板
function highlight(strings, ...values) {
return strings.reduce((result, str, i) =>
result + str + (values[i] ? `<span>${values[i]}</span>` : ''), '');
}
const highlighted = highlight`Hello ${name}!`;
4. 解构赋值 (Destructuring)
快速从数组或对象中提取值。
// 数组解构
const [a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(a, b, rest); // 1, 2, [3, 4, 5]
// 对象解构
const { name, age: userAge, ...otherProps } = {
name: 'Tom',
age: 18,
city: 'New York'
};
console.log(name, userAge, otherProps); // 'Tom', 18, { city: 'New York' }
// 默认值
const { title = 'Untitled' } = {};
console.log(title); // 'Untitled'
// 嵌套解构
const { user: { name: userName } } = { user: { name: 'John' } };
console.log(userName); // 'John'
5. 默认参数、剩余参数、扩展运算符
// 默认参数
function greet(name = 'Guest') {
console.log(`Hello, ${name}!`);
}
// 剩余参数
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
// 扩展运算符
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
// for...of
for (const char of 'hello') {
console.log(char);
}
ES2015 (ES6) - 高级特性
这些高级特性为 JavaScript 带来了面向对象编程、函数式编程和元编程的能力,使 JavaScript 成为一门真正现代化的编程语言。
1. 类和模块 (Classes & Modules)
更接近传统面向对象写法,支持继承和模块化导入导出。
// 类定义
class Person {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, ${this.name}!`);
}
static create(name) {
return new Person(name);
}
}
// 继承
class Employee extends Person {
constructor(name, role) {
super(name);
this.role = role;
}
sayHello() {
super.sayHello();
console.log(`I am a ${this.role}`);
}
}
// 模块导出
export class User extends Person {}
export const helper = () => {};
// 模块导入
import { User, helper } from './user.js';
2. Promise
统一异步编程接口,支持链式调用。
// 基本用法
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('done');
}, 1000);
});
promise
.then(result => console.log(result))
.catch(error => console.error(error));
// 链式调用
fetch('api/data')
.then(response => response.json())
.then(data => processData(data))
.catch(error => handleError(error));
// Promise.all
Promise.all([
fetch('api/users'),
fetch('api/posts')
])
.then(([users, posts]) => {
// 处理所有请求结果
});
// Promise.race
Promise.race([
fetch('api/data'),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), 5000)
)
]);
3. 生成器和迭代器 (Generators & Iterators)
生成器函数可暂停和恢复执行,适合异步流程和自定义迭代。
// 基本生成器
function* generator() {
yield 1;
yield 2;
yield 3;
}
for (const value of generator()) {
console.log(value);
}
// 异步生成器
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
}
// 自定义迭代器
const iterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
};
for (const value of iterable) {
console.log(value);
}
4. Map/Set/WeakMap/WeakSet
新的集合类型,支持任意类型键和值。
// Map
const map = new Map();
map.set('key', 'value');
map.set(1, 'number');
map.set({}, 'object');
// Set
const set = new Set([1, 2, 3, 3, 4]); // 自动去重
console.log([...set]); // [1, 2, 3, 4]
// WeakMap
const weakMap = new WeakMap();
const obj = {};
weakMap.set(obj, 'value');
// 当 obj 被垃圾回收时,对应的值也会被回收
// WeakSet
const weakSet = new WeakSet();
weakSet.add(obj);
// 当 obj 被垃圾回收时,会自动从 weakSet 中移除
5. Symbol
唯一值的基本类型,常用于对象属性名避免冲突。
// 创建 Symbol
const sym1 = Symbol('description');
const sym2 = Symbol('description');
console.log(sym1 === sym2); // false
// 作为对象属性
const obj = {
[sym1]: 'value'
};
// 内置 Symbol
class MyArray extends Array {
static get [Symbol.species]() {
return Array;
}
}
// Symbol.iterator
const iterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
}
};
6. Proxy & Reflect
元编程能力,拦截对象操作。
// Proxy 示例
const target = { foo: 'bar' };
const handler = {
get(obj, prop) {
return prop in obj ? obj[prop] : 'default';
},
set(obj, prop, value) {
if (typeof value === 'string') {
obj[prop] = value;
return true;
}
return false;
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.foo); // 'bar'
console.log(proxy.abc); // 'default'
// Reflect 示例
const obj = { x: 1, y: 2 };
Reflect.set(obj, 'z', 3);
console.log(Reflect.get(obj, 'z')); // 3
7. 字符串、数组、对象新方法
// 字符串新方法
'hello'.includes('ell'); // true
'hello'.startsWith('he'); // true
'hello'.endsWith('lo'); // true
'hello'.repeat(3); // 'hellohellohello'
// 数组新方法
[1, 2, 3].find(x => x > 1); // 2
[1, 2, 3].findIndex(x => x > 1); // 1
Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']
Array.of(1, 2, 3); // [1, 2, 3]
// 对象新方法
Object.assign({}, { a: 1 }, { b: 2 }); // { a: 1, b: 2 }
Object.is(NaN, NaN); // true
Object.setPrototypeOf(obj, proto);
ES2016 (ES7)
ES2016 是一个小版本更新,引入了两个实用的特性。虽然特性不多,但 Array.includes() 成为了日常开发中的常用方法,指数运算符则提供了更简洁的数学运算语法。
1. Array.prototype.includes()
判断数组是否包含某元素,支持 NaN。
const array = [1, 2, NaN];
console.log(array.includes(NaN)); // true
console.log(array.includes(2)); // true
console.log(array.includes(3)); // false
// 与 indexOf 的区别
console.log([NaN].indexOf(NaN)); // -1
console.log([NaN].includes(NaN)); // true
2. 指数运算符 (Exponentiation Operator)
2 ** 3 等价于 Math.pow(2, 3)
const result = 2 ** 3; // 8
const square = 2 ** 2; // 4
const cube = 2 ** 3; // 8
// 与 Math.pow 的区别
console.log(2 ** 3 ** 2); // 512 (右结合)
console.log(Math.pow(2, Math.pow(3, 2))); // 512
ES2017 (ES8)
ES2017 带来了革命性的 async/await 语法,彻底改变了 JavaScript 异步编程的写法,使异步代码看起来像同步代码一样清晰。同时增强了对象操作能力,为现代 JavaScript 开发奠定了重要基础。
1. async/await
基于 Promise 的异步编程语法糖。
// 基本用法
async function fetchData() {
try {
const response = await fetch('api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Error:', error);
}
}
// 并行请求
async function fetchMultiple() {
const [users, posts] = await Promise.all([
fetch('api/users').then(r => r.json()),
fetch('api/posts').then(r => r.json())
]);
return { users, posts };
}
// 异步迭代
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
}
2. Object.values() 和 Object.entries()
快速获取对象的值数组或键值对数组。
const obj = { a: 1, b: 2, c: 3 };
// Object.values
console.log(Object.values(obj)); // [1, 2, 3]
// Object.entries
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
// 转换为 Map
const map = new Map(Object.entries(obj));
3. 字符串补全(String padding)
字符串补全。
// padStart
'x'.padStart(5, 'a'); // 'aaaax'
'123'.padStart(5, '0'); // '00123'
// padEnd
'x'.padEnd(5, 'a'); // 'xaaaa'
'123'.padEnd(5, '0'); // '12300'
// 实际应用
function formatNumber(num) {
return num.toString().padStart(2, '0');
}
console.log(formatNumber(5)); // '05'
4. Object.getOwnPropertyDescriptors
获取对象所有属性描述符。
const obj = {
get name() {
return 'John';
}
};
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors.name.get); // [Function: get name]
// 用于克隆对象
const clone = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
5. SharedArrayBuffer & Atomics
多线程共享内存和原子操作,适合高性能场景。
// 创建共享内存
const buffer = new SharedArrayBuffer(1024);
const view = new Int32Array(buffer);
// 原子操作
Atomics.store(view, 0, 123);
const value = Atomics.load(view, 0);
Atomics.add(view, 0, 1);
ES2018 (ES9)
ES2018 进一步完善了异步编程能力,引入了异步迭代,同时增强了对象操作和正则表达式功能。Rest/Spread 属性的引入使对象操作更加灵活,成为现代 JavaScript 开发的重要工具。
1. 异步迭代 (Async Iteration)
支持 for await...of 语法,异步遍历。
// 异步生成器
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}
// 异步迭代
(async () => {
for await (const value of asyncGenerator()) {
console.log(value);
}
})();
// 实际应用:读取文件流
async function processFile(file) {
for await (const chunk of file.stream()) {
processChunk(chunk);
}
}
2. Rest/Spread 属性
对象剩余/扩展属性。
// 对象解构
const { x, y, ...rest } = { x: 1, y: 2, a: 3, b: 4 };
console.log(rest); // { a: 3, b: 4 }
// 对象合并
const obj1 = { foo: 'bar', x: 42 };
const obj2 = { foo: 'baz', y: 13 };
const clonedObj = { ...obj1 };
const mergedObj = { ...obj1, ...obj2 };
3. Promise.finally()
无论成功失败都会执行。
fetch('api/data')
.then(response => response.json())
.then(data => processData(data))
.catch(error => handleError(error))
.finally(() => {
// 清理工作
cleanup();
});
4. 正则增强
命名捕获组、s 修饰符、后行断言等。
// 命名捕获组
const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const result = re.exec('2023-05-01');
console.log(result.groups.year); // '2023'
// s 修饰符(dotAll)
const re2 = /hello.world/s;
console.log(re2.test('hello\nworld')); // true
// 后行断言
const re3 = /(?<=\$)\d+/;
console.log(re3.exec('$123')); // ['123']
ES2019 (ES10)
ES2019 专注于提升开发体验,引入了实用的数组扁平化方法和对象转换工具。这些特性虽然看似简单,但在日常开发中极大地简化了常见操作,提高了代码的可读性和简洁性。
1. Array.prototype.flat() 和 flatMap()
数组扁平化和映射。
// flat
[1, 2, [3, 4]].flat(); // [1, 2, 3, 4]
[1, 2, [3, 4, [5, 6]]].flat(2); // [1, 2, 3, 4, 5, 6]
// flatMap
[1, 2, 3].flatMap(x => [x, x * 2]); // [1, 2, 2, 4, 3, 6]
// 实际应用
const sentences = ['Hello world', 'How are you'];
const words = sentences.flatMap(s => s.split(' '));
2. Object.fromEntries()
键值对数组转对象。
// 基本用法
const entries = [['name', 'John'], ['age', 30]];
const obj = Object.fromEntries(entries);
console.log(obj); // { name: 'John', age: 30 }
// 实际应用:URL 参数解析
const params = new URLSearchParams('name=John&age=30');
const paramsObj = Object.fromEntries(params);
3. String.trimStart/trimEnd
去除字符串首尾空白。
// trimStart
' hello '.trimStart(); // 'hello '
// trimEnd
' hello '.trimEnd(); // ' hello'
// 实际应用
function formatName(name) {
return name.trimStart().trimEnd();
}
4. 可选 catch 绑定
catch 可以省略 error 参数。
try {
// 可能抛出错误的代码
} catch {
// 不需要使用 error 参数
console.log('An error occurred');
}
ES2020 (ES11)
ES2020 是近年来最具影响力的版本之一,可选链和空值合并操作符彻底改变了 JavaScript 中处理不确定数据的方式,大幅减少了防御性编程代码。BigInt 和动态 import 则为特定场景提供了强大的新能力。
1. 可选链操作符 (Optional Chaining)
安全访问多层嵌套属性。
// 对象属性访问
const value = obj?.prop?.nested?.value;
// 数组元素访问
const first = arr?.[0];
// 函数调用
const result = obj.method?.();
// 实际应用
function getCity(user) {
return user?.address?.city ?? 'Unknown';
}
2. 空值合并操作符 (Nullish Coalescing)
只在 null 或 undefined 时使用默认值。
// 基本用法
const value = null ?? 'default';
const count = 0 ?? 42; // 0
// 与 || 的区别
const value1 = 0 || 42; // 42
const value2 = 0 ?? 42; // 0
// 实际应用
function greet(name) {
return `Hello, ${name ?? 'Guest'}!`;
}
3. BigInt
支持任意精度整数。
// 创建 BigInt
const bigInt = 9007199254740991n;
const bigInt2 = BigInt(9007199254740991);
// 运算
const sum = bigInt + 1n;
const product = bigInt * 2n;
// 实际应用:大数计算
function calculateFactorial(n) {
let result = 1n;
for (let i = 2n; i <= n; i++) {
result *= i;
}
return result;
}
4. Promise.allSettled()
所有 Promise 完成后返回每个结果。
// 基本用法
Promise.allSettled([
Promise.resolve(1),
Promise.reject('error'),
Promise.resolve(3)
]).then(results => {
console.log(results);
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 'error' },
// { status: 'fulfilled', value: 3 }
// ]
});
// 实际应用:批量请求
async function fetchAll(urls) {
const results = await Promise.allSettled(
urls.map(url => fetch(url))
);
return results.map(result =>
result.status === 'fulfilled' ? result.value : null
);
}
5. globalThis
统一全局对象。
// 浏览器环境
console.log(globalThis === window); // true
// Node.js 环境
console.log(globalThis === global); // true
// 实际应用
function getGlobal() {
return globalThis;
}
6. 动态 import
按需异步加载模块。
// 基本用法
const module = await import('./module.js');
// 条件导入
if (condition) {
const { default: Component } = await import('./Component.js');
}
// 实际应用:路由懒加载
const routes = [
{
path: '/about',
component: () => import('./About.js')
}
];
ES2021 (ES12)
ES2021 继续完善语言的实用性,replaceAll()
解决了长期存在的字符串替换痛点,逻辑赋值运算符简化了常见的赋值模式,Promise.any()
丰富了异步编程的选择。
1. String.prototype.replaceAll()
全部替换字符串。
// 基本用法
'hello world'.replaceAll('o', '0'); // 'hell0 w0rld'
// 与 replace 的区别
'hello world'.replace(/o/g, '0'); // 需要正则
'hello world'.replaceAll('o', '0'); // 直接使用字符串
// 实际应用
function sanitizeHTML(str) {
return str.replaceAll('<', '<').replaceAll('>', '>');
}
2. Promise.any()
只要有一个 Promise
成功就返回。
// 基本用法
Promise.any([
Promise.reject('error1'),
Promise.resolve('success'),
Promise.reject('error2')
]).then(result => {
console.log(result); // 'success'
});
// 实际应用:多源数据获取
async function fetchFromAnySource(urls) {
try {
const result = await Promise.any(
urls.map(url => fetch(url).then(r => r.json()))
);
return result;
} catch (error) {
console.error('All requests failed');
}
}
3. 逻辑赋值运算符 (Logical Assignment)
简化赋值逻辑。
// 基本用法
let x = 1;
x ||= 2; // x = x || 2
x &&= 3; // x = x && 3
x ??= 4; // x = x ?? 4
// 实际应用
function updateConfig(config) {
config.timeout ??= 1000;
config.retries ||= 3;
return config;
}
4. WeakRef & FinalizationRegistry
弱引用和终结器,适合缓存等场景。
// WeakRef
const cache = new Map();
function getCachedData(key) {
let ref = cache.get(key);
if (ref) {
const value = ref.deref();
if (value) return value;
}
const value = computeExpensiveValue();
cache.set(key, new WeakRef(value));
return value;
}
// FinalizationRegistry
const registry = new FinalizationRegistry(heldValue => {
console.log(`Cleaning up: ${heldValue}`);
});
registry.register(target, 'some value');
ES2022 (ES13)
ES2022 显著增强了类的功能,引入了私有字段和静态字段,使 JavaScript 的面向对象编程更加完善。
顶层 await 简化了模块的异步初始化,这些特性让 JavaScript 在大型应用开发中更加成熟。
1. Class 字段声明 (Class Fields)
类字段和私有字段。
class Person {
// 公共字段
name = 'John';
// 私有字段
#privateField = 'private';
// 静态字段
static count = 0;
// 私有静态字段
static #privateStaticField = 'private static';
constructor() {
Person.count++;
}
getPrivateField() {
return this.#privateField;
}
}
2. Top-level await
模块顶层直接使用 await
。
// 基本用法
const response = await fetch('api/data');
const data = await response.json();
// 实际应用:模块初始化
const config = await loadConfig();
export const api = createAPI(config);
3. Object.hasOwn()
判断对象自身属性。
// 基本用法
const obj = { prop: 'value' };
console.log(Object.hasOwn(obj, 'prop')); // true
console.log(Object.hasOwn(obj, 'toString')); // false
// 与 hasOwnProperty 的区别
const obj2 = Object.create(null);
obj2.prop = 'value';
console.log(obj2.hasOwnProperty('prop')); // 错误
console.log(Object.hasOwn(obj2, 'prop')); // true
4. Error cause
错误链路。
// 基本用法
try {
throw new Error('fail', { cause: 'reason' });
} catch (e) {
console.log(e.cause); // 'reason'
}
// 实际应用:错误传播
async function fetchData() {
try {
const response = await fetch('api/data');
if (!response.ok) {
throw new Error('HTTP error', {
cause: { status: response.status }
});
}
return response.json();
} catch (error) {
throw new Error('Failed to fetch data', { cause: error });
}
}
ES2023 (ES14)
ES2023 专注于填补功能空白,findLast/findLastIndex
补全了数组查找方法,WeakMap/WeakSet 对 Symbol
的支持增强了元编程能力。虽然特性不多,但都是实用的增强。
1. Array.prototype.findLast / findLastIndex
从数组末尾查找满足条件的元素或索引。
// 基本用法
const arr = [1, 2, 3, 4, 5];
arr.findLast(x => x % 2 === 0); // 4
arr.findLastIndex(x => x % 2 === 0); // 3
// 实际应用:查找最后一个匹配项
const logs = [
{ id: 1, status: 'success' },
{ id: 2, status: 'error' },
{ id: 3, status: 'success' }
];
const lastSuccess = logs.findLast(log => log.status === 'success');
2. Array.prototype.toSorted / toReversed / toSpliced
不可变数组操作方法。
- 原有数组方法会修改原数组,不符合函数式编程理念
- 需要手动复制数组再操作,代码冗长
- 缺乏标准的不可变数组操作方法
const original = [3, 1, 4, 1, 5];
// 不可变排序
const sorted = original.toSorted();
console.log(original); // [3, 1, 4, 1, 5] (未改变)
console.log(sorted); // [1, 1, 3, 4, 5]
// 自定义排序
const people = [
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 },
{ name: 'Charlie', age: 35 }
];
const sortedByAge = people.toSorted((a, b) => a.age - b.age);
// 不可变反转
const reversed = original.toReversed();
console.log(reversed); // [5, 1, 4, 1, 3]
// 不可变拼接
const spliced = original.toSpliced(1, 2, 'a', 'b');
console.log(spliced); // [3, 'a', 'b', 1, 5]
// 组合使用
const data = [10, 5, 8, 3, 1];
const processed = data
.toSorted((a, b) => b - a) // 降序排序
.toSpliced(0, 2) // 移除前两个元素
.toReversed(); // 反转
console.log(processed); // [3, 8]
console.log(data); // [10, 5, 8, 3, 1] (原数组未变)
// 实际应用:状态管理
class TodoList {
constructor(items = []) {
this.items = items;
}
addItem(item) {
return new TodoList(this.items.toSpliced(this.items.length, 0, item));
}
removeItem(index) {
return new TodoList(this.items.toSpliced(index, 1));
}
sortByPriority() {
return new TodoList(this.items.toSorted((a, b) => a.priority - b.priority));
}
reverse() {
return new TodoList(this.items.toReversed());
}
}
// 使用示例
const todos = new TodoList([
{ id: 1, text: 'Learn JavaScript', priority: 2 },
{ id: 2, text: 'Build app', priority: 1 },
{ id: 3, text: 'Deploy', priority: 3 }
]);
const sortedTodos = todos.sortByPriority();
const reversedTodos = sortedTodos.reverse();
2. WeakMap 和 WeakSet 支持 Symbol 键
// 基本用法
const weakMap = new WeakMap();
const symbol = Symbol('key');
weakMap.set(symbol, 'value');
// 实际应用:私有数据存储
const privateData = new WeakMap();
class MyClass {
constructor() {
privateData.set(this, {
secret: 'value'
});
}
getSecret() {
return privateData.get(this).secret;
}
}
4. Hashbang 支持
允许脚本以 #!
开头。
#!/usr/bin/env node
// 现在可以直接运行脚本
console.log('Hello, world!');
ES2024 (ES15)
ES2024 带来了多个重要的实用特性,Object.groupBy()
简化了数据分组操作,Promise.withResolvers()
提供了更灵活的 Promise 创建方式,RegExp
v
标志增强了正则表达式能力,这些特性进一步提升了 JavaScript 的开发效率。
1. ArrayBuffer 和 SharedArrayBuffer 增强
支持可调整大小的 ArrayBuffer 和 SharedArrayBuffer,以及传输功能。
// 可调整大小的 ArrayBuffer
const buffer = new ArrayBuffer(8, { maxByteLength: 16 });
console.log(buffer.resizable); // true
console.log(buffer.maxByteLength); // 16
// 调整大小
buffer.resize(12);
console.log(buffer.byteLength); // 12
// 传输 ArrayBuffer
const newBuffer = buffer.transfer(20);
console.log(newBuffer.byteLength); // 20
console.log(buffer.detached); // true
// SharedArrayBuffer 也支持类似功能
const sharedBuffer = new SharedArrayBuffer(8, { maxByteLength: 16 });
sharedBuffer.grow(12); // 只能增长,不能缩小
2. Promise.withResolvers()
提供便捷的方式创建 Promise 及其 resolve/reject
函数。
// 基本用法
const { promise, resolve, reject } = Promise.withResolvers();
// 异步操作
setTimeout(() => {
resolve('Success!');
}, 1000);
// 实际应用:创建可控制的 Promise
class AsyncQueue {
constructor() {
this.queue = [];
this.processing = false;
}
add(task) {
const { promise, resolve, reject } = Promise.withResolvers();
this.queue.push({ task, resolve, reject });
this.process();
return promise;
}
async process() {
if (this.processing) return;
this.processing = true;
while (this.queue.length > 0) {
const { task, resolve, reject } = this.queue.shift();
try {
const result = await task();
resolve(result);
} catch (error) {
reject(error);
}
}
this.processing = false;
}
}
3. Object.groupBy() 和 Map.groupBy()
根据回调函数结果对数据进行分组。
// Object.groupBy
const users = [
{ name: 'Alice', age: 25, department: 'Engineering' },
{ name: 'Bob', age: 30, department: 'Marketing' },
{ name: 'Charlie', age: 35, department: 'Engineering' }
];
const byDepartment = Object.groupBy(users, user => user.department);
// {
// Engineering: [{ name: 'Alice', ... }, { name: 'Charlie', ... }],
// Marketing: [{ name: 'Bob', ... }]
// }
// Map.groupBy
const ageGroups = Map.groupBy(users, user => {
if (user.age < 30) return 'young';
if (user.age < 40) return 'middle';
return 'senior';
});
// Map {
// 'young' => [{ name: 'Alice', ... }],
// 'middle' => [{ name: 'Bob', ... }, { name: 'Charlie', ... }]
// }
// 实际应用:数据分析
function analyzeData(data) {
const statusGroups = Object.groupBy(data, item => item.status);
const summary = Object.entries(statusGroups).map(([status, items]) => ({
status,
count: items.length,
total: items.reduce((sum, item) => sum + item.value, 0)
}));
return summary;
}
4. RegExp v 标志
增强正则表达式,支持集合表示法和字符串属性。
// 基本用法
const regex = /[\p{Script=Latin}&&[^\p{ASCII}]]/v;
console.log(regex.test('café')); // true
// 集合操作
const emojiRegex = /[\p{Emoji}--\p{ASCII}]/v;
console.log(emojiRegex.test('😀')); // true
console.log(emojiRegex.test('A')); // false
// 字符串字面量
const stringSetRegex = /["hello"|"world"]/v;
console.log(stringSetRegex.test('hello')); // true
// 实际应用:复杂字符匹配
function validateUsername(username) {
// 允许字母、数字,但排除某些特殊字符
const validChars = /^[\p{L}\p{N}--[\p{Emoji}\p{Symbol}]]+$/v;
return validChars.test(username);
}
5. Atomics.waitAsync()
异步等待共享内存变化。
// 基本用法
const sharedBuffer = new SharedArrayBuffer(4);
const view = new Int32Array(sharedBuffer);
// 异步等待
const result = Atomics.waitAsync(view, 0, 0);
if (result.async) {
result.value.then(() => {
console.log('Value changed!');
});
}
// 在另一个线程中
Atomics.store(view, 0, 1);
Atomics.notify(view, 0, 1);
// 实际应用:多线程协调
class SharedCounter {
constructor() {
this.buffer = new SharedArrayBuffer(4);
this.view = new Int32Array(this.buffer);
}
async waitForValue(expectedValue) {
const result = Atomics.waitAsync(this.view, 0, expectedValue);
if (result.async) {
await result.value;
}
return Atomics.load(this.view, 0);
}
increment() {
Atomics.add(this.view, 0, 1);
Atomics.notify(this.view, 0, 1);
}
}
6. String.prototype.isWellFormed() 和 toWellFormed()
检查和确保字符串包含格式良好的 Unicode。
// 检查字符串是否格式良好
const wellFormed = 'Hello 👋';
const malformed = 'Hello \uD83D'; // 孤立的高代理项
console.log(wellFormed.isWellFormed()); // true
console.log(malformed.isWellFormed()); // false
// 修复格式错误的字符串
console.log(malformed.toWellFormed()); // 'Hello �'
// 实际应用:安全的字符串处理
function safeStringOperation(str) {
if (!str.isWellFormed()) {
console.warn('String contains malformed Unicode, fixing...');
str = str.toWellFormed();
}
return str.toUpperCase();
}
// 用于 API 响应处理
function processApiResponse(response) {
if (typeof response === 'string' && !response.isWellFormed()) {
response = response.toWellFormed();
}
return JSON.parse(response);
}
ES2025 (ES16)
ES2025 引入了期待已久的 Iterator Helpers
,为 JavaScript 带来了类似函数式编程语言的数据处理能力。Set 方法扩展完善了集合操作,Promise.try()
统一了同步异步处理,这些特性将显著改善数据处理和函数式编程的体验。
1. Iterator Helpers
为迭代器提供丰富的辅助方法,类似于数组方法。
// 基本用法
function* numbers() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
}
// 链式调用
const result = numbers()
.filter(x => x % 2 === 0)
.map(x => x * 2)
.take(2)
.toArray();
console.log(result); // [4, 8]
// 更多方法
const iterator = numbers();
iterator.drop(2).next().value; // 3
iterator.forEach(x => console.log(x));
iterator.some(x => x > 3); // true
iterator.every(x => x > 0); // true
iterator.find(x => x > 2); // 3
iterator.reduce((acc, x) => acc + x, 0); // 15
// 实际应用:数据流处理
function* fetchData() {
for (let i = 1; i <= 100; i++) {
yield fetch(`/api/data/${i}`).then(r => r.json());
}
}
// 处理前10个有效数据
const validData = fetchData()
.filter(async data => (await data).valid)
.take(10)
.toArray();
2. Set 方法扩展
为 Set 添加数学集合操作方法。
// 基本集合操作
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);
// 并集
const union = setA.union(setB);
console.log([...union]); // [1, 2, 3, 4, 5, 6]
// 交集
const intersection = setA.intersection(setB);
console.log([...intersection]); // [3, 4]
// 差集
const difference = setA.difference(setB);
console.log([...difference]); // [1, 2]
// 对称差集
const symmetricDifference = setA.symmetricDifference(setB);
console.log([...symmetricDifference]); // [1, 2, 5, 6]
// 子集检查
console.log(new Set([1, 2]).isSubsetOf(setA)); // true
console.log(setA.isSupersetOf(new Set([1, 2]))); // true
console.log(setA.isDisjointFrom(new Set([7, 8]))); // true
// 实际应用:权限管理
class PermissionManager {
constructor() {
this.userPermissions = new Map();
this.rolePermissions = new Map();
}
getUserEffectivePermissions(userId) {
const userPerms = this.userPermissions.get(userId) || new Set();
const rolePerms = this.getUserRolePermissions(userId);
return userPerms.union(rolePerms);
}
hasConflictingPermissions(userId, requiredPerms) {
const effectivePerms = this.getUserEffectivePermissions(userId);
return !requiredPerms.isSubsetOf(effectivePerms);
}
}
3. Promise.try()
安全地执行可能同步或异步的函数。
// 基本用法
const result = await Promise.try(() => {
// 可能是同步或异步的函数
return Math.random() > 0.5 ? 'sync' : Promise.resolve('async');
});
// 错误处理
const safeResult = await Promise.try(() => {
if (Math.random() > 0.5) {
throw new Error('Something went wrong');
}
return 'success';
}).catch(error => {
console.error('Caught error:', error.message);
return 'fallback';
});
// 实际应用:统一异步处理
class DataProcessor {
async processData(processor, data) {
return Promise.try(() => processor(data))
.then(result => this.validateResult(result))
.catch(error => this.handleError(error));
}
validateResult(result) {
if (!result || typeof result !== 'object') {
throw new Error('Invalid result format');
}
return result;
}
handleError(error) {
console.error('Processing failed:', error);
return { error: error.message, success: false };
}
}
4. RegExp.escape()
安全地转义字符串用于正则表达式。
// 基本用法
const userInput = 'Hello (world) [test]';
const escaped = RegExp.escape(userInput);
console.log(escaped); // 'Hello \\(world\\) \\[test\\]'
// 创建安全的正则表达式
const regex = new RegExp(RegExp.escape(userInput));
console.log(regex.test('Hello (world) [test]')); // true
// 实际应用:搜索功能
class SearchEngine {
search(text, query) {
const escapedQuery = RegExp.escape(query);
const regex = new RegExp(escapedQuery, 'gi');
return text.match(regex) || [];
}
highlight(text, query) {
const escapedQuery = RegExp.escape(query);
const regex = new RegExp(`(${escapedQuery})`, 'gi');
return text.replace(regex, '<mark>$1</mark>');
}
fuzzySearch(text, query) {
const escapedQuery = RegExp.escape(query);
const fuzzyPattern = escapedQuery.split('').join('.*?');
const regex = new RegExp(fuzzyPattern, 'i');
return regex.test(text);
}
}
5. Float16Array 支持
添加半精度浮点数类型数组支持。
// 创建 Float16Array
const float16Array = new Float16Array(4);
float16Array[0] = 1.5;
float16Array[1] = 2.25;
float16Array[2] = 3.75;
float16Array[3] = 4.125;
console.log(float16Array); // Float16Array [1.5, 2.25, 3.75, 4.125]
// Math.f16round 方法
const rounded = Math.f16round(1.23456789);
console.log(rounded); // 1.234375 (半精度精度)
// DataView 支持
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
view.setFloat16(0, 1.5);
view.setFloat16(2, 2.5);
console.log(view.getFloat16(0)); // 1.5
console.log(view.getFloat16(2)); // 2.5
// 实际应用:图形处理
class ImageProcessor {
constructor(width, height) {
this.width = width;
this.height = height;
// 使用半精度浮点数节省内存
this.pixels = new Float16Array(width * height * 4); // RGBA
}
setPixel(x, y, r, g, b, a = 1.0) {
const index = (y * this.width + x) * 4;
this.pixels[index] = Math.f16round(r);
this.pixels[index + 1] = Math.f16round(g);
this.pixels[index + 2] = Math.f16round(b);
this.pixels[index + 3] = Math.f16round(a);
}
getPixel(x, y) {
const index = (y * this.width + x) * 4;
return {
r: this.pixels[index],
g: this.pixels[index + 1],
b: this.pixels[index + 2],
a: this.pixels[index + 3]
};
}
}
6. JSON 模块导入
支持直接导入 JSON 文件作为模块。
// 导入 JSON 文件
import config from './config.json' with { type: 'json' };
import data from './data.json' with { type: 'json' };
// 使用导入的数据
console.log(config.apiUrl);
console.log(data.users);
// 动态导入
const settings = await import('./settings.json', {
with: { type: 'json' }
});
// 实际应用:配置管理
class ConfigManager {
async loadConfig(environment) {
const configPath = `./config/${environment}.json`;
const config = await import(configPath, {
with: { type: 'json' }
});
return config.default;
}
async loadLocalization(locale) {
const localizationPath = `./i18n/${locale}.json`;
try {
const messages = await import(localizationPath, {
with: { type: 'json' }
});
return messages.default;
} catch (error) {
// 回退到默认语言
const fallback = await import('./i18n/en.json', {
with: { type: 'json' }
});
return fallback.default;
}
}
}
7. 正则表达式修饰符
支持在正则表达式内部启用和禁用修饰符。
// 内联修饰符
const regex1 = /(?i)hello/; // 等价于 /hello/i
const regex2 = /(?-i:WORLD)/i; // 在大小写不敏感模式中,WORLD 部分大小写敏感
// 组合使用
const regex3 = /(?i)hello(?-i: WORLD)/;
console.log(regex3.test('Hello WORLD')); // true
console.log(regex3.test('Hello world')); // false
// 多行模式切换
const regex4 = /^(?m)start.*?(?-m)end$/;
// 实际应用:复杂文本解析
class TextParser {
parseDocument(text) {
// 标题:大小写不敏感
// 内容:大小写敏感
const headerRegex = /(?i)^#\s+(.+)$(?-i)/gm;
const headers = [...text.matchAll(headerRegex)];
return headers.map(match => ({
title: match[1],
level: match[0].indexOf('#') + 1
}));
}
extractCodeBlocks(text) {
// 在多行模式中匹配代码块
const codeRegex = /(?s)```(?i)(\w+)?(?-i)\n(.*?)\n```/g;
const blocks = [...text.matchAll(codeRegex)];
return blocks.map(match => ({
language: match[1] || 'text',
code: match[2]
}));
}
}
草案特性合集 (Draft Features Collection)
1. 装饰器(Decorators,Stage 3)
为类和类成员添加元编程注解和行为扩展。当前状态:Stage 3,预计2025年进入Stage 4
草案提出原因或目的:
- 缺乏标准化的元编程机制
- 需要复杂的代码来实现横切关注点(如日志、验证、缓存)
- 框架间装饰器语法不统一
// 类装饰器
@sealed
class Example {
// 方法装饰器
@readonly
@logged
method() {
return 'Hello World';
}
// 属性装饰器
@validate
name = '';
// 访问器装饰器
@cached
get computedValue() {
return this.expensiveCalculation();
}
}
// 装饰器实现
function sealed(constructor) {
Object.seal(constructor);
Object.seal(constructor.prototype);
return constructor;
}
function readonly(target, context) {
if (context.kind === 'method') {
return function(...args) {
const result = target.call(this, ...args);
Object.freeze(result);
return result;
};
}
}
function logged(target, context) {
return function(...args) {
console.log(`Calling ${context.name} with args:`, args);
const result = target.call(this, ...args);
console.log(`${context.name} returned:`, result);
return result;
};
}
function validate(target, context) {
return {
get() {
return target.get.call(this);
},
set(value) {
if (typeof value !== 'string') {
throw new Error(`${context.name} must be a string`);
}
return target.set.call(this, value);
},
init(value) {
if (typeof value !== 'string') {
throw new Error(`${context.name} must be a string`);
}
return value;
}
};
}
// 实际应用:API 控制器
class UserController {
@authenticated
@rateLimit(100) // 每分钟100次请求
@validate({ schema: userSchema })
async createUser(userData) {
return await this.userService.create(userData);
}
@cached(300) // 缓存5分钟
@authorized('admin')
async getUsers() {
return await this.userService.findAll();
}
}
2. Symbol.metadata(Stage 3)
为类和对象提供元数据存储。当前状态:Stage 3,与装饰器提案密切相关
草案提出原因或目的:
- 缺乏标准的元数据存储机制
- 框架需要自定义元数据系统
- 反射和元编程支持不足
注意:该特性与装饰器提案紧密结合,语法可能随装饰器提案变化
// 基本用法(配合装饰器)
function metadata(data) {
return function(target, context) {
// 在装饰器中设置元数据
if (!target[Symbol.metadata]) {
target[Symbol.metadata] = {};
}
Object.assign(target[Symbol.metadata], data);
return target;
};
}
@metadata({ version: '1.0', author: 'developer' })
class MyClass {
@metadata({ required: true, type: 'string' })
property = 'value';
@metadata({ deprecated: true, since: '2.0' })
oldMethod() {
return 'legacy';
}
@metadata({ async: true, timeout: 5000 })
async newMethod() {
return 'modern';
}
}
// 访问元数据
const classMetadata = MyClass[Symbol.metadata];
console.log(classMetadata); // { version: '1.0', author: 'developer' }
// 实际应用:API 文档生成
class ApiDocGenerator {
static generateDocs(targetClass) {
const metadata = targetClass[Symbol.metadata] || {};
const docs = {
className: targetClass.name,
...metadata,
methods: [],
properties: []
};
// 遍历类的方法和属性
const prototype = targetClass.prototype;
const propertyNames = Object.getOwnPropertyNames(prototype);
propertyNames.forEach(name => {
if (name !== 'constructor') {
const descriptor = Object.getOwnPropertyDescriptor(prototype, name);
if (descriptor && typeof descriptor.value === 'function') {
const methodMetadata = descriptor.value[Symbol.metadata] || {};
docs.methods.push({
name,
...methodMetadata
});
}
}
});
return docs;
}
}
// 使用示例
@metadata({
description: 'User management service',
version: '2.1.0',
tags: ['user', 'auth']
})
class UserService {
@metadata({
description: 'Create a new user',
parameters: [{ name: 'userData', type: 'object', required: true }],
returns: { type: 'Promise<User>', description: 'Created user object' }
})
async createUser(userData) {
// 创建用户逻辑
return { id: 1, ...userData };
}
@metadata({
description: 'Get user by ID',
parameters: [{ name: 'id', type: 'number', required: true }],
returns: { type: 'Promise<User|null>', description: 'User object or null' },
cache: { ttl: 300 }
})
async getUserById(id) {
// 获取用户逻辑
return { id, name: 'John Doe' };
}
@metadata({
description: 'Delete user',
deprecated: true,
since: '2.0.0',
alternative: 'softDeleteUser'
})
async deleteUser(id) {
// 删除用户逻辑
}
}
// 生成 API 文档
const apiDocs = ApiDocGenerator.generateDocs(UserService);
console.log(JSON.stringify(apiDocs, null, 2));
// 运行时元数据检查
class ValidationService {
static validate(instance, methodName, args) {
const method = instance.constructor.prototype[methodName];
const metadata = method[Symbol.metadata];
if (metadata && metadata.parameters) {
metadata.parameters.forEach((param, index) => {
if (param.required && args[index] === undefined) {
throw new Error(`Parameter '${param.name}' is required`);
}
if (param.type && typeof args[index] !== param.type) {
throw new Error(`Parameter '${param.name}' must be of type ${param.type}`);
}
});
}
if (metadata && metadata.deprecated) {
console.warn(`Method '${methodName}' is deprecated since ${metadata.since}`);
if (metadata.alternative) {
console.warn(`Use '${metadata.alternative}' instead`);
}
}
}
}
提案状态说明:
- 目前处于 Stage 3,接近最终确定
- 与装饰器提案紧密结合,共同进退
- 为反射和元编程提供标准化支持
- 预计与装饰器一同在2025年进入 Stage 4
3. 管道操作符(Pipeline Operator,Stage 2)
提供函数式编程风格的数据流处理。当前状态:Stage 2,语法仍在讨论中
草案提出原因或目的:
- 深度嵌套的函数调用难以阅读和维护
- 缺乏清晰的数据流表达方式
- 临时变量污染作用域
当前提案有两种语法选择:
Hack-style 管道(|>)
// 传统写法
const result = Math.round(Math.abs(Math.sqrt(16)));
// 管道操作符写法
const result = 16
|> Math.sqrt(%)
|> Math.abs(%)
|> Math.round(%);
// 复杂数据处理
const processData = data => data
|> %.filter(item => item.active)
|> %.map(item => ({ ...item, processed: true }))
|> %.sort((a, b) => a.priority - b.priority);
// 异步管道
const fetchUserData = userId => userId
|> await fetchUser(%)
|> await fetchUserPosts(%)
|> await enrichWithMetadata(%);
F#-style 管道(|>)
// F# 风格(每个阶段必须是单参数函数)
const result = 16
|> Math.sqrt
|> Math.abs
|> Math.round;
// 需要适配器函数处理多参数
const processUser = user => user
|> validateUser
|> u => updateDatabase(u, { timestamp: Date.now() })
|> u => sendNotification(u, 'updated');
// 实际应用:数据转换管道
const transformApiResponse = response => response
|> JSON.parse
|> data => data.results
|> results => results.filter(item => item.status === 'active')
|> items => items.map(normalizeItem)
|> items => items.sort(byPriority);
提案状态说明:
- 目前 TC39 委员会在两种语法间犹豫
- Hack-style 更灵活但语法复杂
- F#-style 更简洁但限制较多
- 预计2025年确定最终语法方案
4. 部分应用(Partial Application,Stage 1)
允许用 ?
占位符预先填充部分参数,返回新函数。当前状态:Stage 1,提案被重新设计
草案提出原因或目的:
- 手动创建柯里化函数繁琐
- 缺乏标准的部分应用语法
- 函数组合和复用困难
注意:该提案目前处于重新设计阶段,语法可能发生变化
// 基本用法(当前提案语法)
const add = (a, b, c) => a + b + c;
const addFive = add(5, ?, ?);
const addFiveAndThree = add(5, 3, ?);
console.log(addFive(2, 3)); // 10
console.log(addFiveAndThree(1)); // 9
// 复杂参数模式
const processData = (config, data, options, callback) => {
// 数据处理逻辑
};
// 预设配置和选项
const processWithDefaults = processData(defaultConfig, ?, defaultOptions, ?);
// 使用
processWithDefaults(userData, handleResult);
processWithDefaults(apiData, logResult);
// 实际应用:API 调用
const apiCall = (method, url, headers, body) => {
return fetch(url, { method, headers, body });
};
// 预设 API 配置
const postToAPI = apiCall('POST', ?, authHeaders, ?);
const getFromAPI = apiCall('GET', ?, authHeaders, null);
// 使用
const createUser = postToAPI('/users', JSON.stringify(userData));
const fetchUsers = getFromAPI('/users');
// 事件处理应用
const handleEvent = (element, eventType, handler, options) => {
element.addEventListener(eventType, handler, options);
};
// 预设元素和选项
const addClickHandler = handleEvent(button, 'click', ?, { once: true });
const addHoverHandler = handleEvent(?, 'mouseenter', ?, false);
// 使用
addClickHandler(submitForm);
addHoverHandler(tooltip, showTooltip);
提案状态说明:
- 原 Stage 2 提案因复杂性问题被降级
- 目前在重新设计更简洁的语法
- 与管道操作符提案存在语法冲突需要解决
- 预计2025-2026年重新进入 Stage 2
5. 模式匹配(Pattern Matching,Stage 1)
类似于 switch,但支持结构化匹配和解构。当前状态:Stage 1,语法设计中
草案提出原因或目的:
- switch 语句功能有限,不支持复杂匹配
- 缺乏结构化数据的优雅处理方式
- 条件逻辑复杂时代码冗长
注意:语法仍在设计阶段,以下为提案中的语法示例
// 基本模式匹配(提案语法)
const result = match (value) {
when 0 -> 'zero',
when 1 -> 'one',
when Number if (value > 1) -> 'big number',
when String -> 'text',
when _ -> 'unknown'
};
// 对象解构匹配
const handleResponse = match (response) {
when { status: 200, data } -> data,
when { status: 404 } -> null,
when { status, error } if (status >= 400) -> throw new Error(error),
when _ -> response
};
// 数组模式匹配
const processArray = match (arr) {
when [] -> 'empty',
when [x] -> `single: ${x}`,
when [x, y] -> `pair: ${x}, ${y}`,
when [head, ...tail] -> `head: ${head}, tail: ${tail.length}`,
when _ -> 'other'
};
// 复杂嵌套匹配
const handleApiResult = match (result) {
when { success: true, data: { user: { name, age } } } if (age >= 18) ->
`Adult user: ${name}`,
when { success: true, data: { user: { name } } } ->
`Minor user: ${name}`,
when { success: false, error: { code: 404 } } ->
'User not found',
when { success: false, error: { code, message } } ->
`Error ${code}: ${message}`,
when _ -> 'Unknown response format'
};
// 类型匹配(假设有类型系统)
const processValue = match (value) {
when String if (value.length > 10) -> 'long string',
when String -> 'short string',
when Number if (value % 2 === 0) -> 'even number',
when Number -> 'odd number',
when Boolean -> 'boolean value',
when Array -> `array with ${value.length} items`,
when Object -> 'object',
when null -> 'null value',
when undefined -> 'undefined value',
when _ -> 'unknown type'
};
// 实际应用:状态机
const handleState = (state, action) => match ([state, action]) {
when ['idle', { type: 'START' }] -> 'loading',
when ['loading', { type: 'SUCCESS', data }] -> { state: 'success', data },
when ['loading', { type: 'ERROR', error }] -> { state: 'error', error },
when ['success', { type: 'RESET' }] -> 'idle',
when ['error', { type: 'RETRY' }] -> 'loading',
when [currentState, _] -> currentState // 保持当前状态
};
提案状态说明:
- 2018年5月进入 Stage 1
- 语法设计仍在讨论中,存在多个竞争方案
- 需要解决与现有 switch 语句的兼容性
- 性能优化和编译器支持是关键挑战
- 预计2026年后才可能进入 Stage 2
6. 类型注解(Type Annotations,Stage 1)
为 JS 代码添加类型注解,未来可用于类型检查和 IDE 智能提示。当前状态:Stage 1,语法规范制定中
草案提出原因或目的:
- JavaScript 缺乏原生类型系统
- 运行时错误难以在开发阶段发现
- IDE 智能提示和重构支持有限
- TypeScript 需要编译步骤
注意:这是一个仅语法提案,不包含运行时类型检查
// 函数类型注解(提案语法)
function add(a: number, b: number): number {
return a + b;
}
// 变量类型注解
let name: string = 'John';
let age: number = 30;
let isActive: boolean = true;
let items: Array<string> = ['a', 'b', 'c'];
// 对象类型注解
interface User {
id: number;
name: string;
email?: string;
roles: string[];
}
const user: User = {
id: 1,
name: 'Alice',
roles: ['admin']
};
// 类型别名
type Status = 'pending' | 'approved' | 'rejected';
type EventHandler = (event: Event) => void;
// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
function map<T, U>(array: T[], fn: (item: T) => U): U[] {
return array.map(fn);
}
// 类的类型注解
class ApiClient {
private baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
async get<T>(endpoint: string): Promise<T> {
const response = await fetch(`${this.baseUrl}${endpoint}`);
return response.json();
}
async post<T, U>(endpoint: string, data: T): Promise<U> {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
return response.json();
}
}
// 复杂类型组合
interface ApiResponse<T> {
success: boolean;
data?: T;
error?: {
code: number;
message: string;
};
}
type UserCreateRequest = {
name: string;
email: string;
password: string;
};
type UserResponse = ApiResponse<User>;
// 实际应用示例
class UserService {
private client: ApiClient;
constructor(client: ApiClient) {
this.client = client;
}
async createUser(userData: UserCreateRequest): Promise<UserResponse> {
return this.client.post<UserCreateRequest, UserResponse>('/users', userData);
}
async getUser(id: number): Promise<UserResponse> {
return this.client.get<UserResponse>(`/users/${id}`);
}
async updateUser(id: number, updates: Partial<User>): Promise<UserResponse> {
return this.client.post<Partial<User>, UserResponse>(`/users/${id}`, updates);
}
}
提案状态说明:
- 这是一个"仅语法"提案,类型注解在运行时会被忽略
- 目标是让工具(如 TypeScript、Flow)能够直接处理 JS 文件
- 不包含运行时类型检查,保持 JS 的动态特性
- 语法设计需要与 TypeScript 保持兼容
- 预计2025-2026年进入 Stage 2
7. Array.prototype.groupBy(已移至 Object.groupBy,ES2024)
根据回调结果分组数组元素。当前状态:已在 ES2024 中作为 Object.groupBy 实现
草案提出原因或目的:
- 手动分组数组元素代码冗长
- 缺乏标准的数组分组方法
- 需要使用 reduce 等复杂操作
注意:原 Array.prototype.groupBy 提案被重新设计为 Object.groupBy
const people = [
{ name: 'Alice', age: 25, department: 'Engineering' },
{ name: 'Bob', age: 30, department: 'Marketing' },
{ name: 'Charlie', age: 35, department: 'Engineering' },
{ name: 'Diana', age: 28, department: 'Marketing' }
];
// 使用 Object.groupBy(ES2024)
const byDepartment = Object.groupBy(people, person => person.department);
// {
// Engineering: [{ name: 'Alice', ... }, { name: 'Charlie', ... }],
// Marketing: [{ name: 'Bob', ... }, { name: 'Diana', ... }]
// }
// 按年龄段分组
const byAgeGroup = Object.groupBy(people, person => {
if (person.age < 30) return 'young';
return 'senior';
});
// {
// young: [{ name: 'Alice', ... }, { name: 'Diana', ... }],
// senior: [{ name: 'Bob', ... }, { name: 'Charlie', ... }]
// }
// 使用 Map.groupBy 处理非字符串键
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const byParity = Map.groupBy(numbers, n => n % 2 === 0);
// Map {
// false => [1, 3, 5, 7, 9],
// true => [2, 4, 6, 8, 10]
// }
// 复杂分组逻辑
const transactions = [
{ id: 1, amount: 100, type: 'credit', date: '2024-01-15' },
{ id: 2, amount: 50, type: 'debit', date: '2024-01-15' },
{ id: 3, amount: 200, type: 'credit', date: '2024-01-16' },
{ id: 4, amount: 75, type: 'debit', date: '2024-01-16' }
];
// 按日期和类型分组
const byDateAndType = Object.groupBy(transactions, t => `${t.date}-${t.type}`);
// {
// '2024-01-15-credit': [{ id: 1, ... }],
// '2024-01-15-debit': [{ id: 2, ... }],
// '2024-01-16-credit': [{ id: 3, ... }],
// '2024-01-16-debit': [{ id: 4, ... }]
// }
提案演进历史:
- 最初作为 Array.prototype.groupBy 提案
- 因原型污染和性能考虑,改为静态方法
- ES2024 中实现为 Object.groupBy 和 Map.groupBy
- 解决了数组分组的标准化需求
本文档专注于 ES2015-ES2025 各版本的核心特性介绍,为 JavaScript 开发者提供系统性的学习参考。