ES6 新特性 从 ECMAScript 2015(ES6)到 ECMAScript 2025

ES6 新特性 从 ECMAScript 2015(ES6)到 ECMAScript 2025

  • ECMAScript 2015 (ES6)
  • ECMAScript 2016 (ES7)
  • ECMAScript 2017 (ES8)
  • ECMAScript 2018 (ES9)
  • ECMAScript 2019 (ES10)
  • ECMAScript 2020 (ES11)
  • ECMAScript 2021 (ES12)
  • ECMAScript 2022 (ES13)
  • ECMAScript 2023 (ES14)
  • ECMAScript 2024 (ES15) - 已发布的部分特性
  • ECMAScript 2025 (ES16) - 预计的特性

ECMAScript 2015 (ES6) - 2015年6月

let 和 const 变量声明

let 声明的变量具有块级作用域:

js 复制代码
// let - 块级作用域变量
defineFunction() {
  let count = 0;
  if (true) {
    let count = 1; // 不会覆盖外部作用域的变量
    console.log(count); // 输出: 1
  }
  console.log(count); // 输出: 0
}

// const - 常量声明
const PI = 3.14159;
// PI = 3.14; // 报错: Assignment to constant variable
js 复制代码
// 示例
if (true) {
  let x = 5;
  console.log(x); // 5
}
console.log(typeof x); // "undefined",因为x在块外不可访问

// 防止变量提升导致的问题
console.log(y); // undefined (var声明的变量会被提升)
console.log(z); // 报错:Cannot access 'z' before initialization

var y = 10;
let z = 20;

const 声明常量,不可重新赋值:

js 复制代码
// 示例
const PI = 3.14159;
console.log(PI); // 3.14159
// PI = 3; // 报错:Assignment to constant variable

// 对象和数组的引用是常量,但内容可以修改
const person = { name: "John" };
person.name = "Jane"; // 允许
console.log(person); // { name: "Jane" }

箭头函数 (Arrow Functions)

提供简洁的函数定义语法,不绑定自己的 this :

js 复制代码
// 普通函数
function add(a, b) {
  return a + b;
}

// 箭头函数简化写法
const add = (a, b) => a + b;

// 保留this上下文
const obj = {
  name: "Test",
  regularFunction: function() {
    setTimeout(function() {
      console.log(this.name); // 输出: undefined
    }, 100);
  },
  arrowFunction: function() {
    setTimeout(() => {
      console.log(this.name); // 输出: Test
    }, 100);
  }
};
js 复制代码
// 基本语法
const sum = (a, b) => a + b;
console.log(sum(2, 3)); // 5

// 单个参数可以省略括号
const square = x => x * x;
console.log(square(4)); // 16

// 无参数需要括号
const random = () => Math.random();

// 多行函数体需要大括号和return
const greet = name => {
  const message = `Hello, ${name}!`;
  return message;
};

// 保持上下文的this
const obj = {
  name: "Object",
  regularFunc: function() {
    setTimeout(function() {
      console.log(this.name); //  undefined (this指向全局)
    }, 100);
  },
  arrowFunc: function() {
    setTimeout(() => {
      console.log(this.name); // "Object" (this继承自外层)
    }, 100);
  }
};

模板字符串 (Template Literals)

使用反引号定义字符串,支持多行和变量插值:

js 复制代码
const name = "John";
const age = 30;

// 传统字符串拼接
const greeting1 = "Hello, " + name + ". You are " + age + " years old.";

// 模板字符串
const greeting2 = `Hello, ${name}. You are ${age} years old.`;

// 多行字符串
const multiLine = `This is a
multi-line
string.`;
js 复制代码
// 变量插值
const name = "Alice";
const age = 25;
const greeting = `Hello, my name is ${name} and I am ${age} years old.`;
console.log(greeting); // "Hello, my name is Alice and I am 25 years old."

// 多行字符串
const multiLine = `This is line 1
This is line 2
This is line 3`;

// 表达式插值
const a = 10;
const b = 5;
console.log(`${a} + ${b} = ${a + b}`); // "10 + 5 = 15"

解构赋值 (Destructuring Assignment)

从数组或对象中提取值并赋给变量:

js 复制代码
// 对象解构
const user = { name: "Alice", age: 25, city: "New York" };
const { name, age } = user;
console.log(name, age); // 输出: Alice 25

// 数组解构
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first, second, rest); // 输出: 1 2 [3, 4, 5]

// 函数参数解构
function printUser({ name, age }) {
  console.log(`${name} is ${age} years old.`);
}
printUser(user); // 输出: Alice is 25 years old.
js 复制代码
// 数组解构
const [first, second, third] = [1, 2, 3];
console.log(first); // 1
console.log(second); // 2

// 跳过元素
const [x, , z] = [1, 2, 3];
console.log(x); // 1
console.log(z); // 3

// 剩余元素
const [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]

// 对象解构
const person = { firstName: "John", lastName: "Doe", age: 30 };
const { firstName, age } = person;
console.log(firstName); // "John"
console.log(age); // 30

// 重命名
const { firstName: fName, lastName: lName } = person;
console.log(fName); // "John"

// 默认值
const { country = "Unknown" } = person;
console.log(country); // "Unknown"

默认参数

js 复制代码
function greet(name = "Guest", greeting = "Hello") {
  return `${greeting}, ${name}!`;
}

console.log(greet()); // 输出: Hello, Guest!
console.log(greet("Alice")); // 输出: Hello, Alice!
console.log(greet("Bob", "Hi")); // 输出: Hi, Bob!

类 (Classes)

js 复制代码
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  greet() {
    return `Hello, my name is ${this.name}.`;
  }
  
  static createAdult(name) {
    return new Person(name, 18);
  }
}

class Employee extends Person {
  constructor(name, age, position) {
    super(name, age);
    this.position = position;
  }
  
  getJobInfo() {
    return `${this.name} works as ${this.position}.`;
  }
}

const alice = new Person("Alice", 25);
console.log(alice.greet()); // 输出: Hello, my name is Alice.

const bob = Employee.createAdult("Bob");
console.log(bob.getJobInfo()); // 输出: Bob works as undefined.

模块系统 (Modules) - import/export

js 复制代码
// 在 utils.js 中
export const PI = 3.14159;
export function calculateArea(radius) {
  return PI * radius * radius;
}
export default function sayHello() {
  return "Hello from module!";
}

// 在 main.js 中
import sayHello, { PI, calculateArea } from './utils.js';
console.log(sayHello()); // 输出: Hello from module!
console.log(`Area of circle with radius 5: ${calculateArea(5)}`); // 输出: Area of circle with radius 5: 78.53975

Promise

处理异步操作的对象:

js 复制代码
// 创建Promise
const fetchData = new Promise
((resolve, reject) => {
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve("Data fetched successfully");
    } else {
      reject(new Error("Failed to fetch data"));
    }
  }, 1000);
});

// 使用Promise
fetchData
  .then(data => {
    console.log(data); // "Data fetched successfully"
    return data.toUpperCase();
  })
  .then(uppercaseData => {
    console.log(uppercaseData); // "DATA FETCHED SUCCESSFULLY"
  })
  .catch(error => {
    console.error(error);
  })
  .finally(() => {
    console.log("Operation completed");
  });
js 复制代码
function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = Math.random() > 0.5;
      if (success) {
        resolve({ data: "Success!" });
      } else {
        reject(new Error("Failed to fetch data"));
      }
    }, 1000);
  });
}

// 使用 Promise
fetchData()
  .then(result => console.log(result.data))
  .catch(error => console.error(error))
  .finally(() => console.log("Operation completed"));

Map 和 Set 数据结构

js 复制代码
// Map
const userMap = new Map();
userMap.set(1, { name: "Alice", age: 25 });
userMap.set(2, { name: "Bob", age: 30 });

console.log(userMap.get(1)); // 输出: { name: "Alice", age: 25 }
console.log(userMap.size); // 输出: 2

// Set
const numbersSet = new Set([1, 2, 3, 4, 4, 5]);
console.log(numbersSet.size); // 输出: 5 (自动去重)
console.log(numbersSet.has(4)); // 输出: true
numbersSet.add(6);
numbersSet.delete(2);

Symbol 原始数据类型

js 复制代码
// 创建唯一标识符
const id1 = Symbol("id");
const id2 = Symbol("id");
console.log(id1 === id2); // 输出: false

// 作为对象属性键
const user = {
  [id1]: "Unique ID",
  name: "Alice"
};

// Symbol 不会被常规遍历方法获取
console.log(Object.keys(user)); // 输出: ["name"]
console.log(Object.getOwnPropertySymbols(user)); // 输出: [Symbol(id)]

迭代器和生成器 (Iterators & Generators)

js 复制代码
// 迭代器
const iterable = {
  [Symbol.iterator]() {
    let count = 0;
    return {
      next() {
        count++;
        if (count <= 5) {
          return { value: count, done: false };
        } else {
          return { done: true };
        }
      }
    };
  }
};

// 生成器
function* generateSequence() {
  yield 1;
  yield 2;
  yield 3;
}

const generator = generateSequence();
console.log(generator.next().value); // 输出: 1
console.log(generator.next().value); // 输出: 2
console.log(generator.next().value); // 输出: 3

// 生成器函数简化迭代
function* fibonacci() {
  let a = 0, b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

for...of 循环

js 复制代码
const numbers = [1, 2, 3, 4, 5];

// 遍历数组
for (const number of numbers) {
  console.log(number);
}

// 遍历字符串
for (const char of "hello") {
  console.log(char);
}

// 遍历 Map
const userMap = new Map([["name", "Alice"], ["age", 25]]);
for (const [key, value] of userMap) {
  console.log(`${key}: ${value}`);
}

对象字面量增强

js 复制代码
const name = "Alice";
const age = 25;
const greet = function() { return "Hello!"; };

// ES6 增强的对象字面量
const user = {
  // 简写属性
  name,
  age,
  
  // 简写方法
  greet() {
    return "Hello!";
  },
  
  // 计算属性名
  ["prop" + (1 + 2)]: "Computed Property",
  
  // 方法中使用 super
  getGreeting() {
    return super.toString();
  }
};

展开运算符 (Spread Operator)

js 复制代码
// 数组展开
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2); // [1, 2, 3, 4, 5]

// 合并数组
const arr3 = [...arr1, ...arr2];
console.log(arr3); // [1, 2, 3, 1, 2, 3, 4, 5]

// 复制数组
const arrCopy = [...arr1];

// 展开对象
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
console.log(obj2); // { a: 1, b: 2, c: 3 }

// 函数参数展开
function sum(a, b, c) {
  return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6

ECMAScript 2016 (ES7)

Array.prototype.includes()

检查数组是否包含某个元素:

js 复制代码
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // 输出: true
console.log(numbers.includes(6)); // 输出: false

// 从指定索引开始搜索
console.log(numbers.includes(3, 3)); // 输出: false (从索引3开始搜索)
js 复制代码
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true
console.log(numbers.includes(6)); // false

// 从指定索引开始搜索
console.log(numbers.includes(3, 3)); // false (从索引3开始查找)

// 处理NaN
const mixed = [1, 2, NaN, 4];
console.log(mixed.includes(NaN)); // true (与indexOf不同)
console.log(mixed.indexOf(NaN)); // -1

指数运算符 (**)

js 复制代码
// 等同于 Math.pow(2, 3)
console.log(2 ** 3); // 输出: 8
console.log(5 ** 2); // 输出: 25
console.log(10 ** -1); // 输出: 0.1

// 赋值运算符形式
let num = 2;
num **= 3;
console.log(num); // 输出: 8
js 复制代码
console.log(2 ** 3); // 8 (2的3次方)
console.log(10 ** -1); // 0.1 (10的-1次方)

// 与赋值运算符结合
let x = 2;
x **= 3;
console.log(x); // 8

ECMAScript 2017 (ES8)

Async/Await

异步编程语法糖,使异步代码更易读:

js 复制代码
function fetchData() {
  return new Promise(resolve => {
    setTimeout(() => resolve("Data fetched"), 1000);
  });
}

async function processData() {
  try {
    console.log("Start processing");
    const data = await fetchData();
    console.log(data);
    console.log("Processing complete");
  } catch (error) {
    console.error("Error processing data", error);
  }
}

processData();
// 输出:
// Start processing
// Data fetched
// Processing complete
js 复制代码
// 定义异步函数
async function fetchUserData(userId) {
  try {
    // await等待Promise解决
    const response = await fetch(`https://api.example.com/users/${userId}`);
    const userData = await response.json();
    return userData;
  } catch (error) {
    console.error("Error fetching user data:", error);
    throw error;
  }
}

// 使用异步函数
async function displayUser() {
  try {
    const user = await fetchUserData(1);
    console.log(user);
  } catch (error) {
    console.error("Failed to display user", error);
  }
}

displayUser();

Object.values() 和 Object.entries()

js 复制代码
const user = { name: "Alice", age: 25, city: "New York" };

// 获取所有值
const values = Object.values(user);
console.log(values); // 输出: ["Alice", 25, "New York"]

// 获取所有键值对
const entries = Object.entries(user);
console.log(entries); // 输出: [["name", "Alice"], ["age", 25], ["city", "New York"]]

// 使用 for...of 遍历
for (const [key, value] of Object.entries(user)) {
  console.log(`${key}: ${value}`);
}
js 复制代码
const person = { name: "John", age: 30, city: "New York" };

// 获取所有值
console.log(Object.values(person)); // ["John", 30, "New York"]

// 获取所有键值对
console.log(Object.entries(person)); // [["name", "John"], ["age", 30], ["city", "New York"]]

// 遍历对象
for (const [key, value] of Object.entries(person)) {
  console.log(`${key}: ${value}`);
}
// name: John
// age: 30
// city: New York

String.prototype.padStart() 和 String.prototype.padEnd() 方法

js 复制代码
const str = "5";

// 用指定字符填充到指定长度
console.log(str.padStart(3, "0")); // 输出: "005"
console.log(str.padEnd(3, "0")); // 输出: "500"

// 不指定填充字符则默认使用空格
console.log("abc".padStart(5)); // 输出: "  abc"

ECMAScript 2018 (ES9)

异步迭代器 (Async Iterators)

js 复制代码
async function* asyncGenerator() {
  for (let i = 1; i <= 3; i++) {
    // 模拟异步操作
    await new Promise(resolve => setTimeout(resolve, 1000));
    yield i;
  }
}

async function processAsyncIterator() {
  for await (const value of asyncGenerator()) {
    console.log(value);
  }
}

processAsyncIterator();
// 每隔1秒输出: 1, 2, 3

Promise.prototype.finally()

无论Promise成功或失败都会执行的回调:

js 复制代码
fetchData()
  .then(result => console.log(result))
  .catch(error => console.error(error))
  .finally(() => {
    // 无论成功或失败都会执行
    console.log("Operation completed");
    // 可以在这里关闭加载指示器等
  });
js 复制代码
fetchData()
  .then(data => console.log(data))
  .catch(error => console.error
  (error))
  .finally(() => {
    console.log("Operation completed");
    // 这里可以执行清理操作,如隐藏加载指示器
  });

Rest/Spread 属性 用于对象

js 复制代码
// Rest 属性
const user = { name: "Alice", age: 25, city: "New York", country: "USA" };
const { name, age, ...address } = user;
console.log(name); // 输出: Alice
console.log(age); // 输出: 25
console.log(address); // 输出: { city: "New York", country: "USA" }

// Spread 属性
const defaults = { theme: "light", language: "en" };
const settings = { notifications: true, ...defaults };
console.log(settings); // 输出: { notifications: true, theme: "light", language: "en" }

正则表达式命名捕获组

js 复制代码
// 传统捕获组
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const match = regex.exec("2023-10-15");
console.log(match[1]); // "2023"
console.log(match[2]); // "10"
console.log(match[3]); // "15"

// 命名捕获组
const namedRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const namedMatch = namedRegex.exec("2023-10-15");
console.log(namedMatch.groups.year); // "2023"
console.log(namedMatch.groups.month); // "10"
console.log(namedMatch.groups.day); // "15"

// 在replace中使用
const dateStr = "2023-10-15";
const formattedDate = dateStr.
replace(namedRegex, "$<day>/$<month>/$<year>");
console.log(formattedDate); // "15/10/2023"

ECMAScript 2019 (ES10)

Array.prototype.flat() 和 Array.prototype.flatMap()

js 复制代码
// flat() - 展平数组
const nestedArray = [1, [2, 3], [4, [5, 6]]];
console.log(nestedArray.flat()); // 输出: [1, 2, 3, 4, [5, 6]]
console.log(nestedArray.flat(2)); // 输出: [1, 2, 3, 4, 5, 6]

// flatMap() - 映射后展平
const numbers = [1, 2, 3];
const result = numbers.flatMap(n => [n, n * 2]);
console.log(result); // 输出: [1, 2, 2, 4, 3, 6]
js 复制代码
// 展平数组
const nestedArray = [1, [2, 3], [4, [5, 6]]];
console.log(nestedArray.flat()); // [1, 2, 3, 4, [5, 6]]
console.log(nestedArray.flat(2)); // [1, 2, 3, 4, 5, 6] (指定深度)
console.log(nestedArray.flat(Infinity)); // 展平所有层级

// flatMap结合map和flat
const numbers = [1, 2, 3, 4];
const result = numbers.flatMap(n => [n, n * 2]);
console.log(result); // [1, 2, 2, 4, 3, 6, 4, 8]

String.prototype.trimStart() 和 String.prototype.trimEnd() 方法

js 复制代码
const str = "   Hello World!   ";
console.log(str.trimStart()); // 输出: "Hello World!   "
console.log(str.trimEnd()); // 输出: "   Hello World!"
console.log(str.trim()); // 输出: "Hello World!"

Object.fromEntries()

从键值对数组创建对象:

js 复制代码
// 从键值对数组创建对象
const entries = [["name", "Alice"], ["age", 25], ["city", "New York"]];
const user = Object.fromEntries(entries);
console.log(user); // 输出: { name: "Alice", age: 25, city: "New York" }

// 转换 Map 为对象
const map = new Map(entries);
const obj = Object.fromEntries(map);
console.log(obj); // 输出: { name: "Alice", age: 25, city: "New York" }
js 复制代码
const entries = [['name', 'John'], ['age', 30], ['city', 'New York']];
const person = Object.fromEntries(entries);
console.log(person); // { name: 'John', age: 30, city: 'New York' }

// 实际应用:对象转换
const obj = { a: 1, b: 2, c: 3 };
const transformed = Object.fromEntries(
  Object.entries(obj)
    .map(([key, value]) => [key, 
    value * 2])
);
console.log(transformed); // { a: 2, b: 4, c: 6 }

ECMAScript 2020 (ES11)

可选链操作符 (?. )

安全地访问嵌套对象属性:

js 复制代码
const user = {
  name: "Alice",
  address: {
    city: "New York",
    coordinates: { lat: 40.7128, lng: -74.006 }
  }
};

// 安全访问嵌套属性
console.log(user?.address?.city); // 输出: "New York"
console.log(user?.contact?.email); // 输出: undefined (不会抛出错误)

// 安全调用方法
console.log(user.sayHello?.()); // 输出: undefined

// 安全访问数组索引
console.log(user.addresses?.[0]); // 输出: undefined
js 复制代码
const user = {
  profile: {
    name: "John",
    address: {
      city: "New York"
    }
  }
};

// 传统方式需要检查每个层级
const city = user && user.profile && user.profile.address && user.profile.address.city;

// 使用可选链
const cityOptional = user?.profile?.address?.city;
console.log(cityOptional); // "New York"

// 处理不存在的属性
const country = user?.profile?.address?.country;
console.log(country); // undefined (不会报错)

// 可选链与函数调用
const greet = user?.greet?.(); // 如果greet存在则调用,否则返回undefined

空值合并运算符 (?? )

当左侧操作数为null或undefined时,返回右侧操作数:

js 复制代码
// 只有当左侧为 null 或 undefined 时才返回右侧值
const value1 = null ?? "Default";
console.log(value1); // 输出: "Default"

const value2 = undefined ?? "Default";
console.log(value2); // 输出: "Default"

const value3 = "" ?? "Default";
console.log(value3); // 输出: "" (空字符串不触发默认值)

const value4 = 0 ?? "Default";
console.log(value4); // 输出: 0 (0 不触发默认值)
js 复制代码
// 传统逻辑或的问题
const count = 0;
console.log(count || "Not specified"); // "Not specified" (0被视为false)

// 使用空值合并运算符
console.log(count ?? "Not specified"); // 0 (只有null或undefined才返回右侧)

const name = null;
console.log(name ?? "Unknown"); // "Unknown"

const city = undefined;
console.log(city ?? "Default City"); // "Default City"

// 结合可选链
const userCity = user?.profile?.address?.city ?? "Unknown City";

BigInt

处理任意精度整数:

js 复制代码
// 创建 BigInt
const bigNumber = BigInt(9007199254740991); // 最大安全整数
const biggerNumber = 9007199254740991n; // 直接使用 n 后缀

console.log(bigNumber + 1n); // 输出: 9007199254740992n
console.log(biggerNumber * 2n); // 输出: 18014398509481982n

// 注意: BigInt 和 Number 不能直接混合运算
// console.log(bigNumber + 1); // 报错
console.log(bigNumber + BigInt(1)); // 正常工作
js 复制代码
// 创建BigInt
const bigNum1 = BigInt(123456789012345678901234567890);
const bigNum2 = 123456789012345678901234567890n;

// 操作
const sum = bigNum1 + bigNum2;
console.log(sum); // 246913578024691357802469135780n
// 注意:不能直接与普通数字混合运算
// const mixed = bigNum1 + 1; // 报错
const mixed = bigNum1 + BigInt(1); // 正确

// 比较
console.log(BigInt(10) === 10n); // true
console.log(BigInt(10) == 10); // true
console.log(BigInt(10) > 9); // true

ECMAScript 2021 (ES12)

String.prototype.replaceAll() 方法

js 复制代码
const str = "Hello, world! Hello, JavaScript!";
const newStr = str.replaceAll("Hello", "Hi");
console.log(newStr); // 输出: "Hi, world! Hi, JavaScript!"

// 与正则表达式一起使用
const regexStr = str.replaceAll(/Hello/g, "Hey");
console.log(regexStr); // 输出: "Hey, world! Hey, JavaScript!"

逻辑赋值运算符

结合逻辑运算符和赋值:

js 复制代码
// &&= - 只有当左侧为真时才赋值
let x = 1;
x &&= 2; // x 现在是 2

let y = 0;
y &&= 2; // y 保持 0

// ||= - 只有当左侧为假时才赋值
let a = 0;
a ||= 5; // a 现在是 5

let b = 10;
b ||= 5; // b 保持 10

// ??= - 只有当左侧为 null 或 undefined 时才赋值
let c = null;
c ??= 100; // c 现在是 100

let d = "";
d ??= 100; // d 保持 ""
js 复制代码
// 逻辑与赋值 (&&=)
let a = 1;
let b = 2;
a &&= b;
console.log(a); // 2 (相当于 a = a && b)

// 逻辑或赋值 (||=)
let c = null;
let d = "default";
c ||= d;
console.log(c); // "default" (相当于 c = c || d)

// 空值合并赋值 (??=)
let e;
let f = "fallback";
e ??= f;
console.log(e); // "fallback" (相当于 e = e ?? f)

数字分隔符

提高大数字的可读性:

js 复制代码
// 提高大数字的可读性
const billion = 1_000_000_000;
console.log(billion); // 输出: 1000000000

const hexValue = 0xA0_B0_C0;
console.log(hexValue); // 输出: 10514496

const binaryValue = 0b1010_1011;
console.log(binaryValue); // 输出: 171
js 复制代码
const billion = 1_000_000_000;
console.log(billion); // 1000000000

const hexColor = 0xFF_FF_FF; // 白色
console.log(hexColor); // 16777215

const binary = 0b1010_1011;
console.log(binary); // 171

ECMAScript 2022 (ES13)

顶层 await Top-level await 支持

在模块顶层使用await,无需包装在async函数中:

js 复制代码
// 在模块顶层直接使用 await
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log('Data loaded:', data);

export default data;
js 复制代码
// 以前的方式
(async function() {
  const data = await fetchData();
  console.log(data);
})();

// 现在可以直接在模块顶层使用
const data = await fetchData();
console.log(data);

// 实际应用:动态导入
const feature = await import('./feature.js');
feature.initialize();

类字段声明

直接在类中声明实例字段和静态字段:

js 复制代码
class Person {
  // 公共实例字段
  name = "Guest";
  age = 0;
  
  // 私有实例字段
  #id = Math.random();
  
  // 静态公共字段
  static species = "Homo sapiens";
  
  // 静态私有字段
  static #count = 0;
  
  constructor(name, age) {
    this.name = name;
    this.age = age;
    Person.#count++;
  }
  
  // 私有方法
  #generateId() {
    return this.#id;
  }
  
  // 私有 getter
  get #personId() {
    return this.#id;
  }
  
  // 静态方法访问静态私有字段
  static getCount() {
    return Person.#count;
  }
}

const alice = new Person("Alice", 25);
console.log(alice.name); // 输出: Alice
console.log(Person.species); // 输出: Homo sapiens
console.log(Person.getCount()); // 输出: 1
// console.log(alice.#id); // 报错: Private field '#id' must be declared in an enclosing class
js 复制代码
class Person {
  // 公共实例字段
  name = "Anonymous";
  age = 0;
  
  // 私有实例字段 (以#开头)
  #email;
  
  // 静态公共字段
  static species = "Homo sapiens";
  
  // 静态私有字段
  static #count = 0;
  
  constructor(name, age, email) {
    this.name = name;
    this.age = age;
    this.#email = email;
    Person.#count++;
  }
  
  // 私有方法
  #validateEmail() {
    return this.#email.includes('@');
  }
  
  getEmail() {
    if (this.#validateEmail()) {
      return this.#email;
    }
    return "Invalid email";
  }
  
  static getCount() {
    return Person.#count;
  }
}

const john = new Person("John", 30, "john@example.com");
console.log(john.name); // "John"
console.log(john.getEmail()); // "john@example.com"
console.log(Person.species); // "Homo sapiens"
console.log(Person.getCount()); // 1
// console.log(john.#email); // 报错:私有字段不可访问

ECMAScript 2023 (ES14)

数组复制方法 (Change Array by Copy)

js 复制代码
const arr = [1, 2, 3, 4, 5];

// toSorted - 返回排序后的新数组
const sorted = arr.toSorted();
console.log(sorted); // 输出: [1, 2, 3, 4, 5]
console.log(arr); // 原数组不变: [1, 2, 3, 4, 5]

// toReversed - 返回反转后的新数组
const reversed = arr.toReversed();
console.log(reversed); // 输出: [5, 4, 3, 2, 1]

// toSpliced - 返回删除/替换/添加元素后的新数组
const spliced = arr.toSpliced(2, 2, 99, 100);
console.log(spliced); // 输出: [1, 2, 99, 100, 5]

// with - 返回修改指定索引后的新数组
const withItem = arr.with(2, 999);
console.log(withItem); // 输出: [1, 2, 999, 4, 5]

Array.prototype.toSorted()、toReversed()、toSpliced()、with()

这些方法返回新数组,不修改原数组:

js 复制代码
const numbers = [3, 1, 4, 1, 5, 9];

// toSorted - 返回排序后的新数组
const sorted = numbers.toSorted();
console.log(sorted); // [1, 1, 3, 4, 5, 9]
console.log(numbers); // [3, 1, 4,1, 5, 9] (原数组不变)

// toReversed - 返回反转后的新数组
const reversed = numbers.toReversed();
console.log(reversed); // [9, 5, 1,4, 1, 3]

// toSpliced - 类似于splice但返回新数组
const spliced = numbers.toSpliced(2, 2, 10, 11);
console.log(spliced); // [3, 1, 10, 11, 5, 9]

// with - 替换指定索引的元素并返回新数组
const replaced = numbers.with(2, 100);
console.log(replaced); // [3, 1, 100, 1, 5, 9]

Object.hasOwn()

检查对象自身是否有指定属性(更安全的hasOwnProperty替代):

js 复制代码
const person = { name: "John" };
console.log(Object.hasOwn(person, "name")); // true
console.log(Object.hasOwn(person, "toString")); // false (继承的属性)

// 处理对象没有hasOwnProperty方法的情况
const obj = Object.create(null); // 创建没有原型的对象
obj.prop = "value";
console.log(Object.hasOwn(obj, "prop")); // true
// console.log(obj.hasOwnProperty("prop")); // 报错:obj.hasOwnProperty is not a function

ECMAScript 2024 (ES15)

Array.fromAsync()

从异步可迭代对象创建数组:

js 复制代码
// 从异步可迭代对象创建数组
async function example() {
  const asyncIterable = {
    async *[Symbol.asyncIterator]() {
      yield 1;
      await new Promise(r => setTimeout(r, 100));
      yield 2;
      await new Promise(r => setTimeout(r, 100));
      yield 3;
    }
  };
  
  const arr = await Array.fromAsync(asyncIterable);
  console.log(arr); // 输出: [1, 2, 3]
}

example();
js 复制代码
// 示例:从异步生成器创建数组
async function* asyncGenerator() {
  yield 1;
  await new Promise(resolve => 
  setTimeout(resolve, 100));
  yield 2;
  yield 3;
}

async function example() {
  const array = await Array.
  fromAsync(asyncGenerator());
  console.log(array); // [1, 2, 3]
}

example();

// 示例:处理Fetch API响应
async function processFetchResponse
() {
  const response = await fetch('https://api.example.com/data');
  const data = await Array.fromAsync
  (
    response.body.pipeThrough(new TextDecoderStream())
  );
  console.log(data); // 响应数据的数组形式
}

Promise.withResolvers()

简化Promise创建:

js 复制代码
// 简化 Promise 创建
function timeout(ms) {
  const { promise, resolve, reject } = Promise.withResolvers();
  const id = setTimeout(() => {
    resolve(`Timed out after ${ms}ms`);
  }, ms);
  
  // 可以在此处存储 resolve 和 reject 引用供后续使用
  
  return promise;
}

timeout(1000).then(console.log); // 输出: Timed out after 1000ms
js 复制代码
// 传统方式
function createPromise() {
  let resolve, reject;
  const promise = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });
  return { promise, resolve, reject };
}

// 使用withResolvers
function createBetterPromise() {
  return Promise.withResolvers();
}

// 使用示例
const { promise, resolve, reject } = Promise.withResolvers();

promise.then(value => {
  console.log('Resolved with:', value);
}).catch(error => {
  console.error('Rejected with:', error);
});

// 稍后解析
setTimeout(() => {
  resolve('Success!');
}, 1000);

ECMAScript 2025 (ES16) 提案特性

Temporal - 现代化的日期/时间 API (提案中)

js 复制代码
// Temporal 提案 (预计ES16)
// 注意: 以下代码基于当前提案阶段,最终实现可能有所不同

// 创建日期
const today = Temporal.Now.plainDateISO();
console.log(today.toString()); // 输出: 2023-10-15 (示例日期)

// 日期计算
const tomorrow = today.add({ days: 1 });
console.log(tomorrow.toString()); // 输出: 2023-10-16

// 时间计算
const now = Temporal.Now.plainTimeISO();
const meeting = now.add({ hours: 2, minutes: 30 });
console.log(meeting.toString()); // 输出: 14:30:00 (示例时间)

// 处理不同时区
const dateTimeInTokyo = Temporal.Now.zonedDateTimeISO('Asia/Tokyo');
console.log(dateTimeInTokyo.toString());

装饰器 (Decorators) - 类和类元素的元编程 (提案中)

js 复制代码
// 装饰器提案 (预计ES16)
// 注意: 以下代码基于当前提案阶段,最终实现可能有所不同

// 方法装饰器
function log(target, name, descriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function(...args) {
    console.log(`Calling ${name} with args:`, args);
    const result = originalMethod.apply(this, args);
    console.log(`Method ${name} returned:`, result);
    return result;
  };
  return descriptor;
}

class Calculator {
  @log
  add(a, b) {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(5, 3); // 会输出调用日志
相关推荐
GBVFtou3 小时前
vue响应式 track 和trigger 过程
前端
耀耀切克闹灬3 小时前
生成tag号的脚本
前端
搬运达人3 小时前
React v19.2.0更新
前端
电蚊拍3 小时前
ADB 实现手机访问电脑上运行的网站,真机调试H5网站
前端
浩男孩3 小时前
🍀上班摸鱼,手搓了个分页器组件
前端
朕的剑还未配妥3 小时前
vue2项目中使用markdown-it插件教程,同时解决代码块和较长单词不换行问题
前端
清羽_ls3 小时前
前端代码CR小知识点汇总
前端·cr
WestWong3 小时前
基于 Web 技术栈的跨端开发模版
前端
饮水机战神3 小时前
小程序被下架后,我连夜加了个 "安全接口"
前端·javascript