JavaScript Es9、Es10、Es11、Es12、Es13、Es14、Es15新特性总结

根据ESMA标准发布,到2025年新特性发布主要包含以下这些特性,大体包含Es9-Es15新特性更新:

JavaScript Es9

复制代码
/* 
ES9 (ECMAScript 2018) 新特性
官方公布的所有新特性详细说明和使用场景

ES2018 (ES9) 包含以下主要新特性:
1. 异步迭代器 (Asynchronous Iteration)
   - 引入for await...of循环
   - 支持异步可迭代对象
   - 异步生成器简化异步迭代器的创建
   - 适合遍历异步数据源

2. Promise.finally()
   - 无论Promise成功或失败都会执行
   - 用于清理资源、隐藏加载状态
   - 简化Promise链式调用

3. Rest/Spread 属性
   - 剩余属性:从对象中提取部分属性
   - 扩展属性:合并对象、创建浅拷贝
   - 提高对象操作的灵活性

4. 正则表达式改进
   - 命名捕获组:更清晰地标识捕获组
   - 反向断言:根据前面的内容匹配目标
   - dotAll模式:.匹配包括换行符在内的所有字符
   - Unicode属性转义:匹配特定Unicode属性的字符

5. 模板字符串修订
   - 允许在带标签的模板字符串中使用转义序列
   - 提高带标签模板字符串的灵活性

这些特性进一步增强了JavaScript的异步编程能力、对象操作能力和正则表达式功能,提高了代码的可读性和可维护性。
*/







// ===============================
// 1. 异步迭代器 (Asynchronous Iteration)
// ===============================

// 语法:
// for await (const 变量 of 异步可迭代对象) {
//   // 循环体
// }
// 
// 异步可迭代对象需要实现:
// [Symbol.asyncIterator]() {
//   return {
//     next: async () => {
//       return { value: 值, done: 布尔值 };
//     }
//   };
// }

// 使用场景:
// - 遍历异步数据源,如数据流、数据库查询结果
// - 处理多个异步操作的序列
// - 简化异步代码的遍历逻辑
// - 结合async/await使用,提高可读性

// 示例1:基本异步迭代器
const asyncIterable = {
  [Symbol.asyncIterator]() {
    let i = 0;
    return {
      next: async () => {
        if (i < 5) {
          // 模拟异步操作
          await new Promise(resolve => setTimeout(resolve, 100));
          return { value: i++, done: false };
        } else {
          return { done: true };
        }
      }
    };
  }
};

// 使用for await...of遍历
async function iterateAsync() {
  console.log('开始异步迭代:');
  for await (const value of asyncIterable) {
    console.log(`异步迭代值:${value}`);
  }
  console.log('异步迭代结束');
}

iterateAsync();

// 示例2:异步生成器(更简洁的异步迭代器实现)
async function* asyncGenerator() {
  for (let i = 0; i < 5; i++) {
    // 模拟异步操作
    await new Promise(resolve => setTimeout(resolve, 100));
    yield i;
  }
}

async function iterateAsyncGenerator() {
  console.log('\n开始异步生成器迭代:');
  for await (const value of asyncGenerator()) {
    console.log(`异步生成器值:${value}`);
  }
  console.log('异步生成器迭代结束');
}

iterateAsyncGenerator();

// 示例3:实际应用场景 - 模拟异步API调用序列
async function* fetchItems(urls) {
  for (const url of urls) {
    console.log(`正在请求:${url}`);
    // 模拟API请求
    const response = await new Promise(resolve => {
      setTimeout(() => resolve(`来自${url}的数据`), 500);
    });
    yield response;
  }
}

async function fetchAllItems() {
  const urls = ['/api/item1', '/api/item2', '/api/item3'];
  const results = [];
  
  for await (const data of fetchItems(urls)) {
    results.push(data);
    console.log(`收到数据:${data}`);
  }
  
  console.log('\n所有请求完成,结果:', results);
}

fetchAllItems();

// ===============================
// 2. Promise.finally() 方法
// ===============================

// 语法:
// promise.finally(() => {
//   // 无论成功或失败都会执行的代码
// });

// 使用场景:
// - 清理资源,如关闭文件、清除定时器、取消订阅
// - 隐藏加载状态,如关闭加载指示器
// - 确保无论异步操作结果如何,都执行某些代码
// - 简化Promise链式调用中的重复代码

// 示例1:基本使用
function fetchWithFinally(url) {
  console.log(`开始请求:${url}`);
  
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (url) {
        resolve(`成功获取${url}的数据`);
      } else {
        reject('无效的URL');
      }
    }, 1000);
  })
  .then(result => {
    console.log(`请求成功:${result}`);
    return result;
  })
  .catch(error => {
    console.error(`请求失败:${error}`);
    throw error;
  })
  .finally(() => {
    console.log('无论成功失败,都会执行finally');
    // 这里可以执行清理操作,如关闭加载状态
    console.log('关闭加载指示器');
  });
}

// 成功情况
fetchWithFinally('https://api.example.com/data')
  .then(result => console.log(`最终结果:${result}`))
  .catch(error => console.error(`最终错误:${error}`));

// 失败情况
fetchWithFinally('')
  .then(result => console.log(`最终结果:${result}`))
  .catch(error => console.error(`最终错误:${error}`));

// 示例2:结合async/await使用
async function fetchWithAsyncAwait(url) {
  console.log(`\n开始async/await请求:${url}`);
  
  try {
    const result = await new Promise((resolve, reject) => {
      setTimeout(() => {
        if (url) {
          resolve(`成功获取${url}的数据`);
        } else {
          reject('无效的URL');
        }
      }, 1000);
    });
    console.log(`请求成功:${result}`);
    return result;
  } catch (error) {
    console.error(`请求失败:${error}`);
    throw error;
  } finally {
    console.log('无论成功失败,都会执行finally');
    console.log('关闭加载指示器');
  }
}

fetchWithAsyncAwait('https://api.example.com/users');

// ===============================
// 3. Rest/Spread 属性
// ===============================

// 语法:
// 剩余属性:const { 属性1, ...剩余属性 } = 对象;
// 扩展属性:const 新对象 = { ...对象1, ...对象2 };

// 使用场景:
// - 从对象中提取部分属性,剩余属性组成新对象
// - 合并多个对象
// - 创建对象的浅拷贝
// - 向对象添加新属性,同时保留原有属性
// - 函数参数中的对象解构

// 示例1:剩余属性(Rest Properties)
const user = {
  name: '张三',
  age: 28,
  city: '北京',
  email: 'zhangsan@example.com',
  phone: '13800138000'
};

// 提取部分属性,剩余属性组成新对象
const { name, age, ...contactInfo } = user;
console.log(`姓名:${name}`); // 输出: 张三
console.log(`年龄:${age}`); // 输出: 28
console.log('联系方式:', contactInfo); // 输出: { city: '北京', email: 'zhangsan@example.com', phone: '13800138000' }

// 示例2:扩展属性(Spread Properties)
const defaultSettings = {
  theme: 'light',
  fontSize: 14,
  language: 'zh-CN'
};

const userSettings = {
  fontSize: 16,
  notifications: true
};

// 合并对象,userSettings会覆盖defaultSettings中的同名属性
const mergedSettings = { ...defaultSettings, ...userSettings };
console.log('合并后的设置:', mergedSettings);
// 输出: { theme: 'light', fontSize: 16, language: 'zh-CN', notifications: true }

// 示例3:创建对象浅拷贝
const original = { a: 1, b: { c: 2 } };
const copy = { ...original };

console.log(copy); // 输出: { a: 1, b: { c: 2 } }
console.log(copy === original); // 输出: false (不同对象)
console.log(copy.b === original.b); // 输出: true (浅拷贝,嵌套对象还是同一个引用)

// 示例4:在函数参数中使用
function createUser({ name, age, ...otherInfo }) {
  console.log(`创建用户:${name},年龄:${age}`);
  console.log('其他信息:', otherInfo);
  return { id: Math.random().toString(36).substr(2, 9), name, age, ...otherInfo };
}

const newUser = createUser({
  name: '李四',
  age: 30,
  city: '上海',
  email: 'lisi@example.com'
});

console.log('新创建的用户:', newUser);

// ===============================
// 4. 正则表达式改进
// ===============================

// ===============================
// 4.1 命名捕获组 (Named Capture Groups)
// ===============================

// 语法:
// /(?<名称>模式)/

// 使用场景:
// - 更清晰地标识捕获组,提高代码可读性
// - 便于后续引用捕获组,无需记住索引
// - 提高正则表达式的可维护性
// - 适合复杂正则表达式,如日期、URL解析

// 示例1:基本使用
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const dateStr = '2023-12-25';
const match = dateStr.match(dateRegex);

console.log(match); // 完整匹配结果
console.log(`年:${match.groups.year}`); // 输出: 2023
console.log(`月:${match.groups.month}`); // 输出: 12
console.log(`日:${match.groups.day}`); // 输出: 25

// 示例2:在replace中使用命名捕获组
const formattedDate = dateStr.replace(dateRegex, '$<year>年$<month>月$<day>日');
console.log(formattedDate); // 输出: 2023年12月25日

// 示例3:解析URL
const urlRegex = /(?<protocol>https?):\/\/(?<host>[^/:]+)(?<port>:\d+)?(?<path>\/[^?]*)?(?<query>\?.*)?/;
const url = 'https://www.example.com:8080/path/to/resource?param1=value1&param2=value2';
const urlMatch = url.match(urlRegex);

console.log('URL解析结果:');
console.log(`协议:${urlMatch.groups.protocol}`); // 输出: https
console.log(`主机:${urlMatch.groups.host}`); // 输出: www.example.com
console.log(`端口:${urlMatch.groups.port}`); // 输出: :8080
console.log(`路径:${urlMatch.groups.path}`); // 输出: /path/to/resource
console.log(`查询:${urlMatch.groups.query}`); // 输出: ?param1=value1&param2=value2

// ===============================
// 4.2 反向断言 (Lookbehind Assertions)
// ===============================

// 语法:
// 正向后向断言:(?<=模式)目标
// 负向后向断言:(?<!模式)目标

// 使用场景:
// - 根据前面的内容匹配目标
// - 提取特定前缀后的内容
// - 避免匹配某些前缀的内容
// - 更精确的模式匹配

// 示例1:正向后向断言
// 匹配$后面的数字,但不包括$
const priceRegex = /(?<=\$)\d+(\.\d{2})?/;
const priceStr = '商品价格:$19.99,原价$29.99';
const prices = priceStr.match(priceRegex);
console.log(prices); // 输出: ['19.99', '.99', index: 6, input: '商品价格:$19.99,原价$29.99', groups: undefined]

// 全局匹配所有价格
const allPrices = priceStr.match(/(?<=\$)\d+(\.\d{2})?/g);
console.log(allPrices); // 输出: ['19.99', '29.99']

// 示例2:负向后向断言
// 匹配不是$开头的数字
const nonDollarPriceRegex = /(?<!\$)\d+(\.\d{2})?/;
const mixedStr = '价格$19.99,数量100,重量2.5kg';
const nonDollarMatches = mixedStr.match(nonDollarPriceRegex);
console.log(nonDollarMatches); // 输出: ['100', undefined, index: 11, input: '价格$19.99,数量100,重量2.5kg', groups: undefined]

// 全局匹配
const allNonDollarMatches = mixedStr.match(/(?<!\$)\d+(\.\d{2})?/g);
console.log(allNonDollarMatches); // 输出: ['100', '2.5']

// ===============================
// 4.3 dotAll 模式 (s 标志)
// ===============================

// 语法:
// /模式/s

// 使用场景:
// - 让.匹配包括换行符在内的所有字符
// - 适合匹配多行文本
// - 简化跨换行符的模式匹配

// 示例:dotAll模式
const multiLineStr = `第一行
第二行
第三行`;

// 传统模式下,.不匹配换行符
const traditionalRegex = /第一行.第二行/;
console.log(traditionalRegex.test(multiLineStr)); // 输出: false

// 使用dotAll模式,.匹配换行符
const dotAllRegex = /第一行.第二行/s;
console.log(dotAllRegex.test(multiLineStr)); // 输出: true

// 示例2:提取HTML标签内容(包括换行)
const htmlStr = `<div class="content">
  <h1>标题</h1>
  <p>内容</p>
</div>`;

const htmlRegex = /<div class="content">(.*?)<\/div>/s;
const htmlMatch = htmlStr.match(htmlRegex);
console.log(htmlMatch[1]); // 输出: 包含换行的内容

// ===============================
// 4.4 Unicode 属性转义 (Unicode Property Escapes)
// ===============================

// 语法:
// \p{属性名}
// \P{属性名} (否定形式)

// 使用场景:
// - 匹配特定Unicode属性的字符,如字母、数字、符号
// - 支持多种语言的字符匹配
// - 更精确的字符分类
// - 替代传统的字符类,如\w、\d等

// 示例1:匹配所有Unicode字母
const mixedChars = 'Hello 世界 123 🌍';
const letterRegex = /\p{L}+/gu;
console.log(mixedChars.match(letterRegex)); // 输出: ['Hello', '世界']

// 示例2:匹配所有Unicode数字
const digitRegex = /\p{N}+/gu;
console.log(mixedChars.match(digitRegex)); // 输出: ['123']

// 示例3:匹配所有Unicode表情符号
const emojiRegex = /\p{Emoji}/gu;
console.log(mixedChars.match(emojiRegex)); // 输出: ['🌍']

// 示例4:匹配中文汉字
const chineseRegex = /\p{Script=Han}+/gu;
const chineseStr = 'Hello 你好 世界 123';
console.log(chineseStr.match(chineseRegex)); // 输出: ['你好', '世界']

// ===============================
// 5. 模板字符串修订
// ===============================

// 语法:
// 带标签的模板字符串中,允许使用转义序列
// function tag(strings, ...values) {
//   // 处理模板字符串
// }
// tag`模板字符串${变量}`

// 使用场景:
// - 允许在带标签的模板字符串中使用转义序列
// - 提高带标签模板字符串的灵活性
// - 支持更多字符在模板字符串中的使用

// 示例:带标签的模板字符串中的转义序列
function tag(strings, ...values) {
  console.log('模板字符串数组:', strings);
  console.log('插值变量:', values);
  return strings.reduce((result, str, i) => {
    return result + str + (values[i] || '');
  }, '');
}

const name = '张三';
const result = tag`你好,${name}!\n这是换行符\t这是制表符`;
console.log('最终结果:', result);

JavaScript Es10

复制代码
/*
ES10 (ECMAScript 2019) 新特性
官方公布的所有新特性详细说明和使用场景

ES2019 (ES10) 包含以下主要新特性:

1. Array.prototype.flat()
   - 扁平化嵌套数组
   - 支持指定深度或Infinity
   - 自动移除空项

2. Array.prototype.flatMap()
   - 先映射后扁平化
   - 相当于map().flat(1)的简写
   - 更高效的映射+扁平化操作

3. String.prototype.trimStart() 和 String.prototype.trimEnd()
   - 只修剪字符串开头或结尾的空格
   - 替代trimLeft()和trimRight()
   - 适合格式化文本

4. Object.fromEntries()
   - 将键值对数组转换为对象
   - Object.entries()的反向操作
   - 支持Map转换为对象

5. Symbol.prototype.description
   - 获取Symbol的描述字符串
   - 便于调试和日志记录

6. 可选的catch绑定
   - 无需声明catch块中的error参数
   - 简化代码,提高可读性

7. Function.prototype.toString() 修订
   - 返回函数的完整源代码,包括注释和空格
   - 便于调试和代码分析

8. Array.prototype.sort() 稳定性改进
   - 确保排序是稳定的,相等元素保持相对顺序
   - 提高排序结果的可预测性

9. JSON 超集支持
   - 允许JSON中包含U+2028和U+2029字符
   - 与JSON规范完全兼容

10. JSON.stringify() 加强
    - 正确处理特殊Unicode字符
    - 避免抛出错误

这些特性进一步提高了JavaScript的开发效率和代码可读性,尤其是数组操作和对象转换方面的改进,使得处理复杂数据结构更加便捷。
*/


// ===============================
// 1. Array.prototype.flat() 方法
// ===============================

// 语法:
// array.flat(深度)
// 深度默认为1,使用Infinity可以扁平化任意深度

// 使用场景:
// - 扁平化嵌套数组
// - 处理多层嵌套的数据结构
// - 简化数组操作,避免多层循环
// - 适合处理树形结构数据

// 示例1:基本使用
const nestedArr = [1, 2, [3, 4], [5, [6, 7]]];

// 默认深度为1
const flat1 = nestedArr.flat();
console.log(flat1); // 输出: [1, 2, 3, 4, 5, [6, 7]]

// 指定深度为2
const flat2 = nestedArr.flat(2);
console.log(flat2); // 输出: [1, 2, 3, 4, 5, 6, 7]

// 使用Infinity扁平化任意深度
const deeplyNested = [1, [2, [3, [4, [5]]]]];
const flatInfinity = deeplyNested.flat(Infinity);
console.log(flatInfinity); // 输出: [1, 2, 3, 4, 5]

// 示例2:移除空项
const arrWithEmpty = [1, 2, , 4, , 6];
console.log(arrWithEmpty.flat()); // 输出: [1, 2, 4, 6] (自动移除空项)

// 示例3:实际应用场景 - 扁平化菜单数据
const menuData = [
  { name: '首页', path: '/' },
  { 
    name: '产品', 
    path: '/products',
    children: [
      { name: '产品1', path: '/products/1' },
      { name: '产品2', path: '/products/2' }
    ]
  },
  { 
    name: '关于我们', 
    path: '/about',
    children: [
      { 
        name: '公司介绍', 
        path: '/about/company',
        children: [
          { name: '历史', path: '/about/company/history' },
          { name: '团队', path: '/about/company/team' }
        ]
      }
    ]
  }
];

// 扁平化菜单,获取所有路径
function getAllPaths(menu) {
  const paths = [];
  
  function traverse(item) {
    paths.push(item.path);
    if (item.children) {
      for (const child of item.children) {
        traverse(child);
      }
    }
  }
  
  for (const item of menu) {
    traverse(item);
  }
  
  return paths;
}

// 使用flat和flatMap的替代实现
function getAllPathsWithFlat(menu) {
  return menu.flatMap(item => {
    if (item.children) {
      return [item.path, ...getAllPathsWithFlat(item.children)];
    }
    return [item.path];
  });
}

console.log('所有菜单路径:', getAllPaths(menuData));
console.log('使用flatMap获取的菜单路径:', getAllPathsWithFlat(menuData));

// ===============================
// 2. Array.prototype.flatMap() 方法
// ===============================

// 语法:
// array.flatMap(映射函数)
// 相当于 array.map().flat(1)

// 使用场景:
// - 先映射后扁平化数组
// - 替代map+flat的组合,更高效
// - 处理需要同时映射和扁平化的场景
// - 适合生成新数组并扁平化结果

// 示例1:基本使用
const arr = [1, 2, 3, 4];

// 使用map+flat
const mapFlat = arr.map(x => [x, x * 2]).flat();
console.log(mapFlat); // 输出: [1, 2, 2, 4, 3, 6, 4, 8]

// 使用flatMap,更简洁高效
const flatMapped = arr.flatMap(x => [x, x * 2]);
console.log(flatMapped); // 输出: [1, 2, 2, 4, 3, 6, 4, 8]

// 示例2:处理字符串
const sentences = [
  'Hello world',
  'I love JavaScript',
  'ES10 is great'
];

// 分割句子为单词
const words = sentences.flatMap(sentence => sentence.split(' '));
console.log(words); // 输出: ['Hello', 'world', 'I', 'love', 'JavaScript', 'ES10', 'is', 'great']

// 示例3:过滤和映射结合
const numbers = [1, 2, 3, 4, 5];

// 只保留偶数并转换为[num, num*2]格式
const result = numbers.flatMap(num => {
  if (num % 2 === 0) {
    return [[num, num * 2]];
  }
  return []; // 不返回任何内容,相当于过滤
});

console.log(result); // 输出: [[2, 4], [4, 8]]

// ===============================
// 3. String.prototype.trimStart() 和 String.prototype.trimEnd() 方法
// ===============================

// 语法:
// string.trimStart()
// string.trimEnd()

// 使用场景:
// - 只修剪字符串开头的空格
// - 只修剪字符串结尾的空格
// - 替代trimLeft()和trimRight()(它们是别名)
// - 适合格式化文本,如对齐显示

// 示例1:基本使用
const str = '   Hello, World!   ';

console.log(str.trim()); // 输出: 'Hello, World!' (修剪两端空格)
console.log(str.trimStart()); // 输出: 'Hello, World!   ' (只修剪开头空格)
console.log(str.trimEnd()); // 输出: '   Hello, World!' (只修剪结尾空格)

// 示例2:与trimLeft()和trimRight()的关系
console.log(str.trimLeft()); // 输出: 'Hello, World!   ' (trimLeft是trimStart的别名)
console.log(str.trimRight()); // 输出: '   Hello, World!' (trimRight是trimEnd的别名)

// 示例3:实际应用场景 - 格式化用户输入
function formatUserInput(input) {
  // 移除开头的空格,但保留结尾的换行符等格式
  return input.trimStart();
}

const userInput = '   这是用户输入的内容\n\n   带有多行和空格   ';
console.log('格式化前:', JSON.stringify(userInput));
console.log('格式化后:', JSON.stringify(formatUserInput(userInput)));

// ===============================
// 4. Object.fromEntries() 方法
// ===============================

// 语法:
// Object.fromEntries(可迭代对象)
// 可迭代对象的每个元素必须是[key, value]格式

// 使用场景:
// - 将键值对数组转换为对象
// - 替代Object.entries()的反向操作
// - 用于Map转换为对象
// - 适合处理API返回的键值对数据

// 示例1:基本使用
const entries = [['name', '张三'], ['age', 28], ['city', '北京']];
const obj = Object.fromEntries(entries);
console.log(obj); // 输出: { name: '张三', age: 28, city: '北京' }

// 示例2:Map转换为对象
const map = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
]);

const mapToObj = Object.fromEntries(map);
console.log(mapToObj); // 输出: { a: 1, b: 2, c: 3 }

// 示例3:过滤和转换对象属性
const originalObj = {
  name: '张三',
  age: 28,
  email: 'zhangsan@example.com',
  phone: '13800138000'
};

// 只保留指定属性
const filteredObj = Object.fromEntries(
  Object.entries(originalObj).filter(([key, value]) => 
    ['name', 'email'].includes(key)
  )
);

console.log(filteredObj); // 输出: { name: '张三', email: 'zhangsan@example.com' }

// 示例4:转换查询字符串为对象
function parseQueryString(query) {
  if (!query) return {};
  
  // 移除开头的?
  const cleanQuery = query.startsWith('?') ? query.slice(1) : query;
  
  return Object.fromEntries(
    cleanQuery.split('&').map(param => {
      const [key, value] = param.split('=');
      return [decodeURIComponent(key), decodeURIComponent(value)];
    })
  );
}

const queryString = '?name=张三&age=28&city=北京';
console.log(parseQueryString(queryString)); // 输出: { name: '张三', age: '28', city: '北京' }

// ===============================
// 5. Symbol.prototype.description 属性
// ===============================

// 语法:
// symbol.description

// 使用场景:
// - 获取Symbol的描述字符串
// - 替代String(symbol)或symbol.toString()
// - 便于调试和日志记录
// - 适合处理Symbol作为对象属性的场景

// 示例1:基本使用
const sym1 = Symbol('描述文本');
const sym2 = Symbol();

console.log(sym1.description); // 输出: '描述文本'
console.log(sym2.description); // 输出: undefined (没有描述)

// 与传统方式比较
console.log(String(sym1)); // 输出: 'Symbol(描述文本)'
console.log(sym1.toString()); // 输出: 'Symbol(描述文本)'

// 示例2:在对象中使用
const objWithSymbol = {
  [sym1]: 'symbol值',
  [Symbol('另一个描述')]: '另一个symbol值'
};

// 获取所有symbol属性并打印描述
for (const symbol of Object.getOwnPropertySymbols(objWithSymbol)) {
  console.log(`Symbol描述: ${symbol.description}, 值: ${objWithSymbol[symbol]}`);
}

// ===============================
// 6. 可选的catch绑定 (Optional catch binding)
// ===============================

// 语法:
// try {
//   // 可能抛出错误的代码
// } catch {
//   // 处理错误,无需使用error参数
// }

// 使用场景:
// - 不需要使用catch块中的错误对象时
// - 简化代码,提高可读性
// - 适合只需要知道发生错误,但不需要错误详情的场景
// - 如错误恢复、默认值处理等

// 示例1:基本使用
function parseJSON(jsonStr) {
  try {
    return JSON.parse(jsonStr);
  } catch {
    // 不需要错误对象,只需要返回默认值
    return null;
  }
}

console.log(parseJSON('{"name": "张三"}')); // 输出: { name: '张三' }
console.log(parseJSON('无效的JSON')); // 输出: null

// 示例2:与传统catch比较
// 传统方式(必须声明error参数)
try {
  // 代码
} catch (error) {
  // 即使不使用error,也要声明
  console.log('发生错误');
}

// 可选catch绑定(无需声明error参数)
try {
  // 代码
} catch {
  console.log('发生错误');
}

// 示例3:实际应用场景 - 检查环境支持
function checkFeatureSupport() {
  try {
    // 尝试使用某个新特性
    const test = new SomeNewFeature();
    return true;
  } catch {
    // 不关心具体错误,只需要知道不支持
    return false;
  }
}

// ===============================
// 7. Function.prototype.toString() 修订
// ===============================

// 语法:
// function.toString()

// 使用场景:
// - 获取函数的完整源代码,包括注释和空格
// - 便于调试和代码分析
// - 适合序列化函数或生成文档

// 示例1:基本函数
function testFunction(a, b) {
  // 这是一个测试函数
  return a + b;
}

console.log(testFunction.toString());
// 输出完整函数源码,包括注释和空格

// 示例2:箭头函数
const arrowFunc = (x) => {
  return x * x;
};

console.log(arrowFunc.toString());
// 输出: '(x) => {
//   return x * x;
// }'

// 示例3:内置函数
console.log(Array.prototype.map.toString());
// 输出内置map函数的源代码(不同环境可能有所不同)

// ===============================
// 8. Array.prototype.sort() 稳定性改进
// ===============================

// 说明:
// ES2019规范要求sort()方法是稳定的
// 稳定排序意味着相等元素的相对顺序在排序后保持不变

// 使用场景:
// - 对复杂对象进行多次排序
// - 确保排序结果的可预测性
// - 适合需要保持原始顺序的场景

// 示例:稳定排序演示
const items = [
  { name: 'B', value: 2 },
  { name: 'A', value: 1 },
  { name: 'C', value: 2 },
  { name: 'D', value: 1 }
];

// 按value排序
items.sort((a, b) => a.value - b.value);

console.log(items);
// 输出: 
// [
//   { name: 'A', value: 1 },
//   { name: 'D', value: 1 },
//   { name: 'B', value: 2 },
//   { name: 'C', value: 2 }
// ]
// 注意:value相同的元素,原始顺序保持不变(A在D前,B在C前)

// ===============================
// 9. JSON 超集支持
// ===============================

// 说明:
// ES2019允许JSON中包含U+2028(行分隔符)和U+2029(段落分隔符)字符
// 之前这些字符在JSON字符串中会导致语法错误

// 使用场景:
// - 处理包含特殊Unicode字符的JSON数据
// - 确保与JSON规范完全兼容
// - 适合处理来自各种来源的JSON数据

// 示例:支持U+2028和U+2029字符
const jsonWithSpecialChars = '"包含行分隔符\u2028和段落分隔符\u2029的字符串"';
const parsed = JSON.parse(jsonWithSpecialChars);
console.log(parsed); // 输出: '包含行分隔符 和段落分隔符 的字符串'

// ===============================
// 10. JSON.stringify() 加强
// ===============================

// 说明:
// JSON.stringify()现在能够正确处理一些特殊Unicode字符
// 对于超出范围的Unicode字符,会返回转义序列,而不是抛出错误

// 使用场景:
// - 处理包含特殊Unicode字符的数据
// - 确保JSON.stringify()不会抛出错误
// - 适合序列化各种类型的数据

// 示例:处理特殊Unicode字符
const strWithSpecial = '包含\uD800\uDC00( surrogate pair)的字符串';
console.log(JSON.stringify(strWithSpecial));
// 输出: '"包含\ud800\udc00( surrogate pair)的字符串"'

JavaScript Es11

复制代码
/* 
ES11 (ECMAScript 2020) 新特性
官方公布的所有新特性详细说明和使用场景

ES2020 (ES11) 包含以下主要新特性:

1. 可选链操作符 (?.)
   - 安全访问嵌套对象属性,避免TypeError
   - 简化多层嵌套属性的访问代码
   - 支持访问数组元素和调用函数

2. 空值合并运算符 (??)
   - 为null或undefined的值设置默认值
   - 替代||运算符,避免将0、''、false等假值替换为默认值
   - 与可选链结合使用,效果更佳

3. 动态导入 (import())
   - 按需加载模块,提高应用启动性能
   - 条件加载不同模块
   - 适合大型应用的代码分割

4. 顶层await
   - 在模块顶层直接使用await
   - 简化模块初始化的异步操作
   - 适合配置加载、资源初始化等场景

5. BigInt 类型
   - 处理超出Number范围的大整数
   - 精确表示和操作大整数
   - 适合加密、金融、科学计算等场景

6. globalThis 对象
   - 统一访问全局对象,跨环境兼容
   - 替代window、self、global等环境特定的全局对象
   - 提高代码的可移植性

7. String.prototype.matchAll()
   - 获取正则表达式的所有匹配结果,包括捕获组
   - 替代exec()方法的循环调用
   - 支持全局匹配和命名捕获组

8. Promise.allSettled()
   - 并行执行多个异步操作,获取所有结果
   - 不会因为一个Promise失败而中断
   - 适合批量API请求、资源加载等场景

9. 模块命名空间导出的增强语法
   - 简化模块的命名空间导出
   - 提高代码的可读性和可维护性

这些特性进一步增强了JavaScript的表达能力和开发效率,特别是在异步编程、大整数处理、跨环境兼容等方面有了显著提升。
*/


// ===============================
// 1. 可选链操作符 (Optional Chaining Operator) ?.
// ===============================

// 语法:
// 对象?.属性
// 对象?.[表达式]
// 函数?.()

// 使用场景:
// - 安全访问嵌套对象属性,避免TypeError: Cannot read property of undefined
// - 简化多层嵌套属性的访问代码
// - 避免冗长的&&检查
// - 适合处理不确定结构的数据,如API返回结果

// 示例1:基本使用
const user = {
  name: '张三',
  address: {
    city: '北京',
    street: '朝阳区'
    // zipCode 属性不存在
  }
};

// 传统方式(冗长且容易出错)
const city1 = user && user.address && user.address.city;
// 可选链方式(简洁安全)
const city2 = user?.address?.city;
// 访问不存在的属性
const zipCode = user?.address?.zipCode;
// 访问更深层次的不存在属性
const district = user?.profile?.address?.district;

console.log(`城市1:${city1}`); // 输出: 北京
console.log(`城市2:${city2}`); // 输出: 北京
console.log(`邮编:${zipCode}`); // 输出: undefined
console.log(`区县:${district}`); // 输出: undefined

// 示例2:使用可选链访问数组元素
const users = [
  { name: '张三', age: 28 },
  { name: '李四', age: 30 }
];

console.log(users?.[0]?.name); // 输出: 张三
console.log(users?.[2]?.name); // 输出: undefined (访问不存在的数组元素)

// 示例3:使用可选链调用函数
const obj = {
  sayHello() {
    return '你好';
  }
  // sayGoodbye 函数不存在
};

console.log(obj?.sayHello?.()); // 输出: 你好
console.log(obj?.sayGoodbye?.()); // 输出: undefined (调用不存在的函数)

// 示例4:实际应用场景 - 处理API返回数据
function processApiResponse(response) {
  // 安全访问嵌套属性,避免API返回结构变化导致的错误
  const data = {
    userId: response?.data?.user?.id,
    userName: response?.data?.user?.name,
    posts: response?.data?.posts?.map(post => ({
      id: post?.id,
      title: post?.title
    })) || []
  };
  
  return data;
}

// 模拟API返回数据
const apiResponse = {
  data: {
    user: {
      id: 1,
      name: '张三'
    },
    posts: [
      { id: 1, title: '文章1' },
      { id: 2, title: '文章2' }
    ]
  }
};

console.log(processApiResponse(apiResponse));
console.log(processApiResponse({})); // 处理空响应,不会报错

// ===============================
// 2. 空值合并运算符 (Nullish Coalescing Operator) ??
// ===============================

// 语法:
// 表达式1 ?? 表达式2
// 如果表达式1为null或undefined,则返回表达式2,否则返回表达式1

// 使用场景:
// - 为变量设置默认值,只在值为null或undefined时生效
// - 替代||运算符,避免将0、''、false等假值替换为默认值
// - 适合处理可能包含假值的变量

// 示例1:基本使用
const values = {
  name: '', // 空字符串
  age: 0, // 数字0
  city: null,
  country: undefined
};

// 传统 || 运算符的问题:会将0、''、false等假值替换为默认值
console.log(`传统name:${values.name || '默认名称'}`); // 输出: 默认名称 (''被视为假值)
console.log(`传统age:${values.age || 18}`); // 输出: 18 (0被视为假值)

// 空值合并运算符:只在值为null或undefined时才使用默认值
console.log(`?? name:${values.name ?? '默认名称'}`); // 输出: '' (空字符串不是null/undefined)
console.log(`?? age:${values.age ?? 18}`); // 输出: 0 (0不是null/undefined)
console.log(`?? city:${values.city ?? '默认城市'}`); // 输出: 默认城市 (null是nullish值)
console.log(`?? country:${values.country ?? '默认国家'}`); // 输出: 默认国家 (undefined是nullish值)

// 示例2:与可选链结合使用
const userProfile = {
  name: '张三'
  // address 属性不存在
};

// 安全访问嵌套属性并提供默认值
const userCity = userProfile?.address?.city ?? '未知城市';
console.log(userCity); // 输出: 未知城市

// 示例3:实际应用场景 - 配置项默认值
function createConfig(options) {
  return {
    // 只有当options.timeout为null或undefined时,才使用默认值3000
    timeout: options?.timeout ?? 3000,
    // 只有当options.enabled为null或undefined时,才使用默认值true
    enabled: options?.enabled ?? true,
    // 只有当options.retries为null或undefined时,才使用默认值3
    retries: options?.retries ?? 3
  };
}

// 测试各种配置情况
console.log(createConfig({})); // 所有默认值
console.log(createConfig({ timeout: 5000 })); // 自定义timeout
console.log(createConfig({ enabled: false })); // enabled为false,不会使用默认值true
console.log(createConfig({ retries: 0 })); // retries为0,不会使用默认值3

// ===============================
// 3. 动态导入 (Dynamic Import)
// ===============================

// 语法:
// import(模块路径)
// 返回一个Promise,解析为模块对象

// 使用场景:
// - 按需加载模块,提高应用启动性能
// - 条件加载模块,根据不同条件加载不同模块
// - 懒加载,只在需要时才加载模块
// - 适合大型应用的代码分割

// 示例1:基本使用
/*
// 动态导入一个模块
async function loadModule() {
  try {
    const module = await import('./math.js');
    console.log(module.add(2, 3)); // 输出: 5
    console.log(module.default(2, 3)); // 输出: 6 (如果有默认导出)
  } catch (error) {
    console.error('模块加载失败:', error);
  }
}

loadModule();
*/

// 示例2:条件加载
async function loadFeature(featureName) {
  try {
    let feature;
    
    // 根据条件加载不同模块
    switch (featureName) {
      case 'chart':
        feature = await import('./chart.js');
        break;
      case 'map':
        feature = await import('./map.js');
        break;
      case 'editor':
        feature = await import('./editor.js');
        break;
      default:
        throw new Error(`未知特性: ${featureName}`);
    }
    
    feature.init();
  } catch (error) {
    console.error('特性加载失败:', error);
  }
}

// 示例3:实际应用场景 - React组件懒加载
/*
// React中使用动态导入实现组件懒加载
const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
  return (
    <React.Suspense fallback={<div>加载中...</div>}>
      <LazyComponent />
    </React.Suspense>
  );
}
*/

// ===============================
// 4. 顶层await (Top-level await)
// ===============================

// 语法:
// // 在模块顶层直接使用await
// const module = await import('./module.js');

// 使用场景:
// - 模块初始化时的异步操作
// - 配置加载,如加载环境变量或配置文件
// - 资源初始化,如连接数据库
// - 简化异步模块的使用

// 示例:顶层await的使用
/*
// 模块顶层
const config = await fetch('/api/config').then(res => res.json());
export const API_BASE_URL = config.apiBaseUrl;
export const API_KEY = config.apiKey;

// 其他模块可以直接使用,无需处理Promise
import { API_BASE_URL } from './config.js';
console.log(API_BASE_URL); // 直接使用配置值
*/

// 示例2:实际应用场景 - 数据库连接
/*
// db.js 模块
import { createConnection } from 'mysql2/promise';

// 顶层await初始化数据库连接
const connection = await createConnection({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'mydb'
});

export { connection };

// 在其他模块中直接使用连接
import { connection } from './db.js';
async function queryData() {
  const [rows] = await connection.execute('SELECT * FROM users');
  return rows;
}
*/

// ===============================
// 5. BigInt 类型
// ===============================

// 语法:
// const bigInt1 = 123n;
// const bigInt2 = BigInt(123);

// 使用场景:
// - 处理超出JavaScript Number类型范围的整数
// - 精确表示和操作大整数
// - 适合处理加密、金融、科学计算等场景
// - 与其他语言的大整数类型交互

// 示例1:基本使用
const bigInt1 = 123n;
const bigInt2 = BigInt(456);
const bigInt3 = BigInt('789');

console.log(bigInt1); // 输出: 123n
console.log(bigInt2); // 输出: 456n
console.log(bigInt3); // 输出: 789n

// 示例2:BigInt运算
const sum = bigInt1 + bigInt2;
const difference = bigInt2 - bigInt1;
const product = bigInt1 * bigInt2;
const quotient = bigInt2 / bigInt1;
const remainder = bigInt2 % bigInt1;

console.log(`和:${sum}`); // 输出: 579n
console.log(`差:${difference}`); // 输出: 333n
console.log(`积:${product}`); // 输出: 56088n
console.log(`商:${quotient}`); // 输出: 3n (整数除法,舍去小数部分)
console.log(`余数:${remainder}`); // 输出: 99n

// 示例3:BigInt与Number的比较
const num = 123;
const big = 123n;

console.log(num == big); // 输出: true (宽松相等,类型转换)
console.log(num === big); // 输出: false (严格相等,类型不同)
console.log(num < big); // 输出: false
console.log(num <= big); // 输出: true

// 示例4:处理超出Number范围的大整数
// Number类型可以安全表示的最大整数是2^53 - 1
const maxSafeInteger = Number.MAX_SAFE_INTEGER;
console.log(maxSafeInteger); // 输出: 9007199254740991

// 超出范围的整数,Number会丢失精度
const unsafeNum = maxSafeInteger + 1;
const unsafeNum2 = maxSafeInteger + 2;
console.log(unsafeNum === unsafeNum2); // 输出: true (精度丢失,两个不同的数相等)

// BigInt可以精确表示任意大的整数
const safeBigInt1 = BigInt(maxSafeInteger) + 1n;
const safeBigInt2 = BigInt(maxSafeInteger) + 2n;
console.log(safeBigInt1); // 输出: 9007199254740992n
console.log(safeBigInt2); // 输出: 9007199254740993n
console.log(safeBigInt1 === safeBigInt2); // 输出: false (精确表示,不丢失精度)

// 示例5:实际应用场景 - 处理大ID
function generateBigId() {
  // 生成一个大整数ID,适合分布式系统
  return BigInt(Date.now()) * 1000n + BigInt(Math.floor(Math.random() * 1000));
}

const bigId = generateBigId();
console.log(`生成的大ID:${bigId}`); // 输出类似: 1672531200000123n

// ===============================
// 6. globalThis 对象
// ===============================

// 语法:
// globalThis

// 使用场景:
// - 统一访问全局对象,无论在什么环境(浏览器、Node.js、Web Workers等)
// - 替代window、self、global等环境特定的全局对象
// - 适合跨环境的JavaScript代码
// - 提高代码的可移植性和兼容性

// 示例1:基本使用
console.log(globalThis); // 输出当前环境的全局对象

// 在浏览器中:globalThis === window
// 在Node.js中:globalThis === global
// 在Web Workers中:globalThis === self

// 示例2:跨环境代码
function getGlobalObject() {
  // 传统方式(需要处理不同环境)
  /*
  let globalObj;
  if (typeof window !== 'undefined') {
    globalObj = window;
  } else if (typeof self !== 'undefined') {
    globalObj = self;
  } else if (typeof global !== 'undefined') {
    globalObj = global;
  } else {
    throw new Error('无法确定全局对象');
  }
  return globalObj;
  */
  
  // 使用globalThis(简洁统一)
  return globalThis;
}

console.log(getGlobalObject() === globalThis); // 输出: true

// 示例3:在函数中使用globalThis
function setGlobalVar(name, value) {
  globalThis[name] = value;
}

setGlobalVar('myGlobalVar', '这是一个全局变量');
console.log(globalThis.myGlobalVar); // 输出: 这是一个全局变量

// ===============================
// 7. String.prototype.matchAll() 方法
// ===============================

// 语法:
// string.matchAll(正则表达式)
// 返回一个迭代器,包含所有匹配结果

// 使用场景:
// - 获取正则表达式的所有匹配结果,包括捕获组
// - 替代exec()方法的循环调用
// - 适合需要获取所有匹配项详细信息的场景
// - 支持全局匹配和捕获组

// 示例1:基本使用
const str = 'Hello 123, World 456, Welcome 789';
const regex = /(\w+) (\d+)/g;

// 传统方式:使用exec()循环
let match;
console.log('使用exec()方法:');
while ((match = regex.exec(str)) !== null) {
  console.log(`匹配:${match[0]}, 单词:${match[1]}, 数字:${match[2]}`);
}

// 重置正则表达式的lastIndex
regex.lastIndex = 0;

// 使用matchAll()方法
console.log('\n使用matchAll()方法:');
for (const match of str.matchAll(regex)) {
  console.log(`匹配:${match[0]}, 单词:${match[1]}, 数字:${match[2]}`);
}

// 示例2:将迭代器转换为数组
const matches = [...str.matchAll(regex)];
console.log('\n匹配结果数组:');
console.log(matches);

// 示例3:使用named capture groups
const dateStr = '2023-12-25, 2024-01-01';
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/g;

for (const match of dateStr.matchAll(dateRegex)) {
  console.log(`日期:${match[0]}`);
  console.log(`年:${match.groups.year}, 月:${match.groups.month}, 日:${match.groups.day}`);
}

// ===============================
// 8. Promise.allSettled() 方法
// ===============================

// 语法:
// Promise.allSettled(可迭代对象)
// 返回一个Promise,解析为所有Promise的结果数组
// 每个结果对象包含status(fulfilled或rejected)和对应的value或reason

// 使用场景:
// - 并行执行多个异步操作,无论成功或失败都要获取结果
// - 与Promise.all()不同,不会因为一个Promise失败而中断
// - 适合需要处理所有异步操作结果的场景
// - 如批量API请求、资源加载等

// 示例1:基本使用
const promise1 = Promise.resolve('成功1');
const promise2 = Promise.reject('失败2');
const promise3 = Promise.resolve('成功3');

Promise.allSettled([promise1, promise2, promise3])
  .then(results => {
    console.log('Promise.allSettled 结果:');
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        console.log(`Promise ${index + 1} 成功:${result.value}`);
      } else {
        console.log(`Promise ${index + 1} 失败:${result.reason}`);
      }
    });
  });

// 对比 Promise.all()(一个失败就会中断)
Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log('Promise.all 结果:', results);
  })
  .catch(error => {
    console.log('Promise.all 失败:', error);
  });

// 示例2:实际应用场景 - 批量加载资源
async function loadAllResources(urls) {
  const promises = urls.map(url => {
    return fetch(url)
      .then(response => response.json())
      .catch(error => {
        // 捕获错误,避免影响其他请求
        return Promise.reject(`加载 ${url} 失败: ${error.message}`);
      });
  });
  
  const results = await Promise.allSettled(promises);
  
  // 分离成功和失败的结果
  const successfulResults = results
    .filter(result => result.status === 'fulfilled')
    .map(result => result.value);
    
  const failedResults = results
    .filter(result => result.status === 'rejected')
    .map(result => result.reason);
    
  return {
    successful: successfulResults,
    failed: failedResults,
    total: results.length
  };
}

// 模拟资源URLs
const resourceUrls = [
  'https://api.example.com/data1',
  'https://api.example.com/data2',
  'https://api.example.com/invalid-url',
  'https://api.example.com/data3'
];

// 调用函数
loadAllResources(resourceUrls).then(result => {
  console.log('\n资源加载结果:');
  console.log(`成功:${result.successful.length}个`);
  console.log(`失败:${result.failed.length}个`);
  console.log(`总计:${result.total}个`);
});

// ===============================
// 9. 模块命名空间导出的增强语法
// ===============================

// 语法:
// export * as 命名空间 from '模块路径';

// 使用场景:
// - 简化模块的命名空间导出
// - 替代先import再export的方式
// - 适合组织和导出多个模块
// - 提高代码的可读性和可维护性

// 示例:
/*
// 传统方式
import * as math from './math.js';
export { math };

// 增强语法
// export * as math from './math.js';

// 在其他模块中使用
import { math } from './index.js';
console.log(math.add(2, 3));
*/

JavaScript Es12

复制代码
/* 
ES12 (ECMAScript 2021) 新特性
官方公布的所有新特性详细说明和使用场景

ES2021 (ES12) 包含以下主要新特性:

1. String.prototype.replaceAll()
   - 替换字符串中所有匹配项
   - 替代传统replace()需要使用全局正则表达式的方式
   - 简化文本替换操作

2. Promise.any()
   - 只要有一个Promise成功就返回其结果
   - 所有都失败才返回失败
   - 提高系统容错性,适合构建高可用系统

3. 逻辑赋值运算符
   - &&=: 逻辑与赋值,只有左边为真时才赋值
   - ||=: 逻辑或赋值,只有左边为假时才赋值
   - ??=: 空值合并赋值,只有左边为null或undefined时才赋值
   - 简化条件赋值语句,提高代码可读性

4. 数字分隔符
   - 使用下划线分隔数字,提高可读性
   - 支持各种数字类型(整数、小数、二进制、十六进制等)
   - 适合金融、科学计算等领域

5. WeakRef 和 FinalizationRegistry
   - WeakRef: 创建对象的弱引用,不会阻止垃圾回收
   - FinalizationRegistry: 跟踪对象生命周期,在对象被回收后执行清理
   - 适合缓存、资源管理等场景,需要谨慎使用

这些特性进一步增强了JavaScript的表达能力和开发效率,特别是在字符串处理、异步编程、赋值操作和内存管理方面有了显著提升。
*/


// ===============================
// 1. String.prototype.replaceAll() 方法
// ===============================

// 语法:
// string.replaceAll(搜索值, 替换值)

// 使用场景:
// - 替换字符串中所有匹配的子字符串,无需使用全局正则表达式
// - 简化多个相同替换的操作
// - 提高代码可读性,更直观易懂
// - 适合处理文本替换,如格式化、清理数据等

// 示例1:基本使用
const str = 'Hello, World! Hello, JavaScript!';

// 传统方式:需要使用全局正则表达式
const result1 = str.replace(/Hello/g, 'Hi');
// 使用replaceAll():更简洁直观
const result2 = str.replaceAll('Hello', 'Hi');

console.log(`原始字符串:${str}`);
console.log(`使用正则replace结果:${result1}`); // 输出: Hi, World! Hi, JavaScript!
console.log(`使用replaceAll结果:${result2}`); // 输出: Hi, World! Hi, JavaScript!

// 示例2:使用replaceAll()替换特殊字符
const text = '苹果,香蕉,橙子,苹果,葡萄,苹果';
console.log(text.replaceAll('苹果', '梨子')); // 输出: 梨子,香蕉,橙子,梨子,葡萄,梨子

// 示例3:与正则表达式结合使用
const regexStr = 'Hello 123, Hello 456, Hello 789';
// 使用全局正则表达式
console.log(regexStr.replaceAll(/Hello \d+/g, 'Hi')); // 输出: Hi, Hi, Hi

// 示例4:实际应用场景 - 清理用户输入
function sanitizeInput(input) {
  return input
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('&', '&amp;')
    .replaceAll('"', '&quot;')
    .replaceAll("'", '&#39;');
}

const userInput = '<script>alert("恶意脚本");</script>';
console.log('清理前:', userInput);
console.log('清理后:', sanitizeInput(userInput));

// ===============================
// 2. Promise.any() 方法
// ===============================

// 语法:
// Promise.any(可迭代对象)
// 只要有一个Promise成功就返回其结果,所有都失败才返回失败

// 使用场景:
// - 从多个API获取数据,只要有一个成功就使用
// - 提高系统容错性,一个服务不可用还有其他备选
// - 与Promise.all()(所有成功才成功)、Promise.race()(第一个完成,无论成功失败)互补
// - 适合构建高可用系统

// 示例1:基本使用
const promiseSuccess1 = new Promise((resolve) => {
  setTimeout(() => resolve('成功1'), 300);
});

const promiseSuccess2 = new Promise((resolve) => {
  setTimeout(() => resolve('成功2'), 200);
});

const promiseSuccess3 = new Promise((resolve) => {
  setTimeout(() => resolve('成功3'), 100);
});

// 只要有一个成功就返回
Promise.any([promiseSuccess1, promiseSuccess2, promiseSuccess3])
  .then(result => {
    console.log('Promise.any 成功结果:', result); // 输出: 成功3(最快成功的)
  })
  .catch(error => {
    console.error('Promise.any 失败:', error);
  });

// 示例2:所有Promise都失败的情况
const promiseFail1 = Promise.reject('失败1');
const promiseFail2 = Promise.reject('失败2');
const promiseFail3 = Promise.reject('失败3');

Promise.any([promiseFail1, promiseFail2, promiseFail3])
  .then(result => {
    console.log('Promise.any 成功结果:', result);
  })
  .catch(error => {
    console.error('Promise.any 失败:', error); // 输出: AggregateError: All promises were rejected
    console.error('所有失败原因:', error.errors); // 输出: ['失败1', '失败2', '失败3']
  });

// 示例3:与其他Promise方法的比较
const promiseA = new Promise(resolve => setTimeout(() => resolve('A成功'), 100));
const promiseB = new Promise(resolve => setTimeout(() => resolve('B成功'), 50));
const promiseC = new Promise((resolve, reject) => setTimeout(() => reject('C失败'), 75));

console.log('=== Promise.any() ===');
Promise.any([promiseA, promiseB, promiseC]).then(console.log); // 输出: B成功

console.log('=== Promise.race() ===');
Promise.race([promiseA, promiseB, promiseC]).then(console.log, console.error); // 输出: C失败(最快完成的,虽然是失败)

console.log('=== Promise.all() ===');
Promise.all([promiseA, promiseB]).then(console.log, console.error); // 输出: ['A成功', 'B成功']

// 示例4:实际应用场景 - 从多个CDN加载资源
async function loadResourceFromCDN(urls) {
  const promises = urls.map(url => {
    return fetch(url)
      .then(response => {
        if (!response.ok) {
          throw new Error(`加载 ${url} 失败: ${response.status}`);
        }
        return response.text();
      });
  });
  
  try {
    const content = await Promise.any(promises);
    console.log('成功从CDN加载资源');
    return content;
  } catch (error) {
    console.error('所有CDN都加载失败:', error);
    throw new Error('无法加载资源');
  }
}

// 模拟CDN URL列表
const cdnUrls = [
  'https://cdn1.example.com/resource.js',
  'https://cdn2.example.com/resource.js',
  'https://cdn3.example.com/resource.js'
];

loadResourceFromCDN(cdnUrls)
  .then(content => console.log('资源内容:', content.slice(0, 50) + '...'))
  .catch(error => console.error('加载失败:', error));

// ===============================
// 3. 逻辑赋值运算符
// ===============================

// 语法:
// &&=: 逻辑与赋值,只有左边为真时才赋值
// ||=: 逻辑或赋值,只有左边为假时才赋值
// ??=: 空值合并赋值,只有左边为null或undefined时才赋值

// 使用场景:
// - 简化条件赋值语句
// - 提高代码可读性
// - 减少不必要的赋值操作
// - 适合设置默认值、更新状态等场景

// 示例1:&&= 逻辑与赋值
let a = 10;
a &&= 20; // 等同于 a = a && 20; (10 && 20 = 20)
console.log(a); // 输出: 20

let b = 0;
b &&= 20; // 0 && 20 = 0
console.log(b); // 输出: 0

// 示例2:||= 逻辑或赋值
let c = '';
c ||= '默认值'; // 等同于 c = c || '默认值'; ('', 假值,所以赋值)
console.log(c); // 输出: 默认值

let d = '已有值';
d ||= '默认值'; // '已有值' 是真值,所以不赋值
console.log(d); // 输出: 已有值

// 示例3:??= 空值合并赋值
let e = null;
e ??= '默认值'; // 等同于 e = e ?? '默认值'; (null 是nullish值,所以赋值)
console.log(e); // 输出: 默认值

let f = 0;
f ??= '默认值'; // 0 不是nullish值,所以不赋值
console.log(f); // 输出: 0

let g = '';
g ??= '默认值'; // '' 不是nullish值,所以不赋值
console.log(g); // 输出: ''

// 示例4:实际应用场景 - 配置对象合并
function mergeConfig(options) {
  // 只有当options中的属性为null或undefined时,才使用默认值
  options.timeout ??= 3000;
  options.retries ??= 3;
  options.enabled ??= true;
  
  // 只有当enabled为true时,才设置interval
  options.enabled &&= {
    ...options.enabled,
    interval: options.timeout / options.retries
  };
  
  return options;
}

// 测试配置合并
const config1 = { timeout: 5000 };
console.log('合并配置1:', mergeConfig(config1));

const config2 = { enabled: false };
console.log('合并配置2:', mergeConfig(config2));

const config3 = {};
console.log('合并配置3:', mergeConfig(config3));

// ===============================
// 4. 数字分隔符 (Numeric Separators)
// ===============================

// 语法:
// 数字_数字
// 可以在数字之间使用下划线分隔,提高可读性

// 使用场景:
// - 提高大数字的可读性
// - 便于快速识别数字的位数
// - 支持整数、小数、二进制、八进制、十六进制等
// - 适合金融、科学计算等领域

// 示例1:十进制整数
const billion1 = 1000000000; // 传统方式,难以快速识别位数
const billion2 = 1_000_000_000; // 使用分隔符,可读性更强
console.log(billion1 === billion2); // 输出: true

// 示例2:十进制小数
const pi = 3.141_592_653_589_793;
console.log(pi); // 输出: 3.141592653589793

// 示例3:二进制
const binary = 0b1010_1011_1100_1101;
console.log(binary); // 输出: 43981

// 示例4:八进制
const octal = 0o123_456_700;
console.log(octal); // 输出: 34239744

// 示例5:十六进制
const hex = 0x1A2B_3C4D_5E6F;
console.log(hex); // 输出: 43904110237295

// 示例6:科学计数法
const scientific = 1.23e-4_567;
console.log(scientific); // 输出: 1.23e-4567

// 示例7:实际应用场景 - 金融金额
const price1 = 19999.99; // 传统方式
const price2 = 19_999.99; // 使用分隔符,更直观
console.log(`价格1: ${price1}元`);
console.log(`价格2: ${price2}元`);

// 示例8:使用数字分隔符的注意事项
// 不能在数字开头或结尾
// const invalid1 = _123; // 错误
// const invalid2 = 123_; // 错误

// 不能在小数点旁边
// const invalid3 = 12_.34; // 错误
// const invalid4 = 12._34; // 错误

// 不能在科学计数法的e/E旁边
// const invalid5 = 12e_34; // 错误

// ===============================
// 5. WeakRef 和 FinalizationRegistry
// ===============================

// 语法:
// const weakRef = new WeakRef(目标对象);
// const registry = new FinalizationRegistry(回调函数);
// registry.register(目标对象, 关联值, 清理令牌);

// 使用场景:
// - 创建对象的弱引用,不会阻止垃圾回收
// - 跟踪对象的生命周期,在对象被回收后执行清理操作
// - 适合缓存、事件监听器清理、资源管理等场景
// - 需要谨慎使用,避免依赖不确定的垃圾回收时机

// 示例1:WeakRef 基本使用
let obj = { name: '测试对象' };
let weakRef = new WeakRef(obj);

console.log('弱引用获取对象:', weakRef.deref()); // 输出: { name: '测试对象' }

// 解除强引用,让对象可以被垃圾回收
obj = null;

// 手动触发垃圾回收(在Node.js中需要使用--expose-gc并调用global.gc())
// 注意:浏览器环境中无法手动触发,垃圾回收时机不确定
if (typeof global.gc === 'function') {
  global.gc();
  console.log('垃圾回收后弱引用获取对象:', weakRef.deref()); // 可能输出: undefined
}

// 示例2:FinalizationRegistry 基本使用
const registry = new FinalizationRegistry((heldValue) => {
  console.log(`对象被垃圾回收了,关联值: ${heldValue}`);
});

let obj2 = { name: '要被跟踪的对象' };
// 注册对象,关联值为'obj2-finalizer'
registry.register(obj2, 'obj2-finalizer');

// 解除强引用
obj2 = null;

if (typeof global.gc === 'function') {
  global.gc(); // 手动触发垃圾回收
}

// 示例3:实际应用场景 - 缓存实现
class WeakCache {
  constructor() {
    this.cache = new Map();
    this.registry = new FinalizationRegistry(key => {
      // 当值被垃圾回收后,清理缓存中的键
      this.cache.delete(key);
      console.log(`缓存项 ${key} 已清理`);
    });
  }
  
  set(key, value) {
    this.cache.set(key, new WeakRef(value));
    // 注册清理
    this.registry.register(value, key);
  }
  
  get(key) {
    const weakRef = this.cache.get(key);
    return weakRef ? weakRef.deref() : undefined;
  }
  
  has(key) {
    return this.cache.has(key) && this.cache.get(key).deref() !== undefined;
  }
}

// 使用WeakCache
const cache = new WeakCache();

// 添加缓存项
const cachedObj = { data: '缓存数据' };
cache.set('key1', cachedObj);
console.log('缓存中是否有key1:', cache.has('key1')); // 输出: true
console.log('获取缓存:', cache.get('key1')); // 输出: { data: '缓存数据' }

// 解除强引用
cachedObj = null;

// 触发垃圾回收(如果支持)
if (typeof global.gc === 'function') {
  global.gc();
  setTimeout(() => {
    console.log('垃圾回收后缓存中是否有key1:', cache.has('key1')); // 输出: false
  }, 0);
}

JavaScript Es13

复制代码
/*
ES13 (ECMAScript 2022) 新特性
官方公布的所有新特性详细说明和使用场景

ES2022 (ES13) 包含以下主要新特性:

1. 类的私有属性和方法
   - 使用#前缀定义私有属性和方法
   - 封装类的内部状态和实现细节
   - 提高类的安全性和封装性
   - 支持静态私有属性和方法

2. 顶层await
   - 在模块顶层直接使用await
   - 简化模块初始化的异步操作
   - 适合配置加载、资源初始化等场景

3. Array.prototype.at()
   - 支持正索引和负索引访问数组元素
   - 更简洁地访问数组的最后一个元素
   - 提高代码可读性

4. Object.hasOwn()
   - 替代Object.prototype.hasOwnProperty.call()
   - 更安全地检查对象自身属性
   - 避免hasOwnProperty被覆盖的问题

5. Error.cause
   - 支持错误链追踪
   - 保留原始错误信息
   - 便于调试和错误分析

6. RegExp 匹配索引
   - 使用/d标志获取匹配的精确位置
   - 包含完整匹配和捕获组的索引信息
   - 适合文本高亮、替换等场景

7. 模板字符串的标签函数改进
   - 更好地支持嵌套模板字符串
   - 提高标签函数的灵活性
   - 适合国际化、本地化等场景

8. 类的静态块
   - 类加载时执行的静态初始化逻辑
   - 支持复杂的静态属性初始化
   - 处理静态属性之间的依赖关系

这些特性进一步增强了JavaScript的面向对象能力、异步编程支持、数组操作、错误处理和正则表达式功能,提高了代码的可读性、安全性和开发效率。
*/


// ===============================
// 1. 类的私有属性和方法 (Private Fields and Methods)
// ===============================

// 语法:
// class 类名 {
//   #私有属性;
//   
//   constructor() {
//     this.#私有属性 = 值;
//   }
//   
//   #私有方法() {
//     // 方法体
//   }
//   
//   公共方法() {
//     this.#私有方法();
//   }
// }

// 使用场景:
// - 封装类的内部状态和实现细节
// - 避免外部访问和修改内部属性
// - 提高类的封装性和安全性
// - 适合构建复杂的类层次结构

// 示例1:基本使用
class Person {
  // 私有属性
  #name;
  #age;
  
  constructor(name, age) {
    this.#name = name;
    this.#age = age;
  }
  
  // 公共方法访问私有属性
  getName() {
    return this.#name;
  }
  
  getAge() {
    return this.#age;
  }
  
  // 私有方法
  #validateAge(age) {
    return age > 0 && age < 150;
  }
  
  // 公共方法调用私有方法
  setAge(newAge) {
    if (this.#validateAge(newAge)) {
      this.#age = newAge;
      return true;
    }
    return false;
  }
}

const person = new Person('张三', 28);
console.log(person.getName()); // 输出: 张三
console.log(person.getAge()); // 输出: 28
console.log(person.setAge(30)); // 输出: true
console.log(person.getAge()); // 输出: 30
console.log(person.setAge(200)); // 输出: false(调用私有方法验证失败)

// 外部无法直接访问私有属性和方法
// console.log(person.#name); // 语法错误
// console.log(person.#validateAge(30)); // 语法错误

// 示例2:静态私有属性和方法
class Counter {
  // 静态私有属性
  static #count = 0;
  
  // 静态私有方法
  static #increment() {
    this.#count++;
  }
  
  // 静态公共方法
  static next() {
    this.#increment();
    return this.#count;
  }
  
  static getCount() {
    return this.#count;
  }
}

console.log(Counter.next()); // 输出: 1
console.log(Counter.next()); // 输出: 2
console.log(Counter.getCount()); // 输出: 2

// 示例3:私有字段检测(in操作符支持)
class TestClass {
  #privateField;
  
  hasPrivateField() {
    return #privateField in this;
  }
}

const test = new TestClass();
console.log(test.hasPrivateField()); // 输出: true

// ===============================
// 2. 顶层await (Top-level await)
// ===============================

// 语法:
// // 在模块顶层直接使用await
// const module = await import('./module.js');

// 使用场景:
// - 模块初始化时的异步操作
// - 配置加载,如加载环境变量或配置文件
// - 资源初始化,如连接数据库
// - 简化异步模块的使用

// 示例:顶层await的使用
/*
// 模块顶层
const config = await fetch('/api/config').then(res => res.json());
export const API_BASE_URL = config.apiBaseUrl;
export const API_KEY = config.apiKey;

// 其他模块可以直接使用,无需处理Promise
import { API_BASE_URL } from './config.js';
console.log(API_BASE_URL); // 直接使用配置值
*/

// 示例2:实际应用场景 - 数据库连接
/*
// db.js 模块
import { createConnection } from 'mysql2/promise';

// 顶层await初始化数据库连接
const connection = await createConnection({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'mydb'
});

export { connection };

// 在其他模块中直接使用连接
import { connection } from './db.js';
async function queryData() {
  const [rows] = await connection.execute('SELECT * FROM users');
  return rows;
}
*/

// ===============================
// 3. Array.prototype.at() 方法
// ===============================

// 语法:
// array.at(索引)
// 支持正索引和负索引,负索引表示从末尾开始计数

// 使用场景:
// - 访问数组的最后一个或倒数第n个元素
// - 替代array[array.length - 1]的写法
// - 提高代码可读性
// - 适合需要访问数组末尾元素的场景

// 示例1:基本使用
const numbers = [1, 2, 3, 4, 5];

// 传统方式访问最后一个元素
console.log(numbers[numbers.length - 1]); // 输出: 5
// 使用at()方法访问最后一个元素
console.log(numbers.at(-1)); // 输出: 5

// 访问倒数第二个元素
console.log(numbers.at(-2)); // 输出: 4
// 访问第一个元素
console.log(numbers.at(0)); // 输出: 1
// 访问超出范围的索引
console.log(numbers.at(10)); // 输出: undefined
console.log(numbers.at(-10)); // 输出: undefined

// 示例2:与其他数组方法结合使用
const fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry'];

// 获取数组的最后一个元素并转换为大写
const lastFruit = fruits.at(-1).toUpperCase();
console.log(lastFruit); // 输出: ELDERBERRY

// 示例3:实际应用场景 - 处理用户输入历史
class InputHistory {
  constructor(maxSize = 10) {
    this.history = [];
    this.maxSize = maxSize;
  }
  
  addInput(input) {
    this.history.push(input);
    if (this.history.length > this.maxSize) {
      this.history.shift();
    }
  }
  
  // 获取最近的输入
  getRecent(n = 1) {
    return this.history.at(-n);
  }
  
  // 获取最近的n个输入
  getRecentN(n = 3) {
    return this.history.slice(-n);
  }
}

const history = new InputHistory();
history.addInput('第一个输入');
history.addInput('第二个输入');
history.addInput('第三个输入');
history.addInput('第四个输入');

console.log(history.getRecent()); // 输出: 第四个输入
console.log(history.getRecent(2)); // 输出: 第三个输入
console.log(history.getRecentN(2)); // 输出: ['第三个输入', '第四个输入']

// ===============================
// 4. Object.hasOwn() 方法
// ===============================

// 语法:
// Object.hasOwn(对象, 属性名)
// 检查对象自身是否有指定的属性(不包括继承的属性)

// 使用场景:
// - 替代Object.prototype.hasOwnProperty.call()
// - 更安全地检查对象自身属性
// - 避免hasOwnProperty被覆盖的问题
// - 适合需要准确检查对象自身属性的场景

// 示例1:基本使用
const obj = {
  name: '张三',
  age: 28
};

console.log(Object.hasOwn(obj, 'name')); // 输出: true(对象自身有name属性)
console.log(Object.hasOwn(obj, 'toString')); // 输出: false(toString是继承的属性)
console.log(Object.hasOwn(obj, 'age')); // 输出: true
console.log(Object.hasOwn(obj, 'gender')); // 输出: false
console.log(Object.hasOwn(obj, 'gender'));

// 示例2:与hasOwnProperty的比较
// 传统方式:容易被覆盖
const objWithOwnHasOwnProperty = {
  hasOwnProperty: function() {
    return false;
  }
};

// 传统方式会失败
// console.log(objWithOwnHasOwnProperty.hasOwnProperty('name')); // 输出: false(被覆盖)
// 使用Object.hasOwn不会受影响
console.log(Object.hasOwn(objWithOwnHasOwnProperty, 'name')); // 输出: false

// 示例3:处理原型链
const parent = { parentProp: '父属性' };
const child = Object.create(parent);
child.childProp = '子属性';

console.log(Object.hasOwn(child, 'childProp')); // 输出: true(自身属性)
console.log(Object.hasOwn(child, 'parentProp')); // 输出: false(继承属性)
console.log(child.parentProp); // 输出: 父属性(可以访问继承属性)

// 示例4:实际应用场景 - 安全的属性遍历
function safeGetOwnPropertyNames(obj) {
  const ownProps = [];
  for (const prop in obj) {
    if (Object.hasOwn(obj, prop)) {
      ownProps.push(prop);
    }
  }
  return ownProps;
}

const testObj = {
  a: 1,
  b: 2
};

// 添加一个继承属性
Object.prototype.c = 3;

console.log('所有属性(包括继承):', Object.keys(testObj)); // 输出: ['a', 'b'](Object.keys只返回自身可枚举属性)
console.log('使用for...in遍历:', safeGetOwnPropertyNames(testObj)); // 输出: ['a', 'b'](只返回自身属性)

// 删除原型链上的属性
delete Object.prototype.c;

// ===============================
// 5. Error.cause 属性
// ===============================

// 语法:
// new Error('错误信息', { cause: 原始错误 });

// 使用场景:
// - 错误链追踪,保留原始错误信息
// - 更详细的错误诊断
// - 便于调试和错误分析
// - 适合复杂系统中的错误处理

// 示例1:基本使用
function fetchData(url) {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        throw new Error(`HTTP错误: ${response.status}`, { cause: response });
      }
      return response.json();
    })
    .catch(error => {
      // 包装错误,保留原始错误
      throw new Error(`获取数据失败: ${error.message}`, { cause: error });
    });
}

// 调用函数并处理错误
fetchData('https://api.example.com/invalid-url')
  .then(data => console.log(data))
  .catch(error => {
    console.error('最终错误:', error.message);
    console.error('原始错误:', error.cause.message);
    console.error('错误堆栈:', error.stack);
    // 可以继续访问更深层次的错误
    if (error.cause.cause) {
      console.error('HTTP响应:', error.cause.cause.status);
    }
  });

// 示例2:自定义错误类支持cause
class DatabaseError extends Error {
  constructor(message, cause) {
    super(message, { cause });
    this.name = 'DatabaseError';
  }
}

function queryDatabase(query) {
  try {
    // 模拟数据库查询错误
    throw new Error('数据库连接失败');
  } catch (error) {
    throw new DatabaseError(`查询失败: ${query}`, error);
  }
}

try {
  queryDatabase('SELECT * FROM users');
} catch (error) {
  console.error(`${error.name}: ${error.message}`); // 输出: DatabaseError: 查询失败: SELECT * FROM users
  console.error(`原因: ${error.cause.message}`); // 输出: 原因: 数据库连接失败
}

// ===============================
// 6. RegExp 匹配索引
// ===============================

// 语法:
// const regex = /模式/d;
// const match = regex.exec(字符串);
// match.indices // 包含匹配的起始和结束索引

// 使用场景:
// - 获取正则表达式匹配的精确位置
// - 用于文本高亮、替换和分析
// - 适合编辑器、IDE等需要精确位置信息的场景

// 示例1:基本使用
const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/d;
const dateStr = '今天是2023-12-25,明天是2024-01-01';
const match = regex.exec(dateStr);

console.log('完整匹配:', match[0]); // 输出: 2023-12-25
console.log('年:', match.groups.year); // 输出: 2023
console.log('月:', match.groups.month); // 输出: 12
console.log('日:', match.groups.day); // 输出: 25

// indices属性包含匹配的起始和结束索引
console.log('匹配索引:', match.indices);
// 输出:
// {
//   0: [3, 13], // 完整匹配的起始和结束索引
//   1: [3, 7],  // 第一个捕获组(年)的索引
//   2: [8, 10], // 第二个捕获组(月)的索引
//   3: [11, 13], // 第三个捕获组(日)的索引
//   groups: {
//     year: [3, 7],
//     month: [8, 10],
//     day: [11, 13]
//   }
// }

// 示例2:全局匹配的索引
const globalRegex = /\b\w+\b/dg;
const text = 'Hello World';
let matchResult;

console.log('全局匹配索引:');
while ((matchResult = globalRegex.exec(text)) !== null) {
  console.log(`匹配: ${matchResult[0]}, 索引: [${matchResult.indices[0][0]}, ${matchResult.indices[0][1]}]`);
}
// 输出:
// 匹配: Hello, 索引: [0, 5]
// 匹配: World, 索引: [6, 11]

// 示例3:实际应用场景 - 文本高亮
function highlightText(text, pattern) {
  const regex = new RegExp(pattern, 'dg');
  let result = '';
  let lastIndex = 0;
  let match;
  
  while ((match = regex.exec(text)) !== null) {
    const [start, end] = match.indices[0];
    // 添加匹配前的文本
    result += text.slice(lastIndex, start);
    // 添加高亮的匹配文本
    result += `<span class="highlight">${text.slice(start, end)}</span>`;
    lastIndex = end;
  }
  
  // 添加剩余文本
  result += text.slice(lastIndex);
  
  return result;
}

const htmlText = highlightText('今天是2023-12-25,明天是2024-01-01', '\d{4}-\d{2}-\d{2}');
console.log('高亮后的HTML:', htmlText);

// ===============================
// 7. 模板字符串的标签函数改进
// ===============================

// 语法:
// function tag(strings, ...values) {
//   // 处理模板字符串
//   return processedString;
// }
// tag`模板字符串${变量}`

// 使用场景:
// - 更灵活地处理模板字符串
// - 支持嵌套模板字符串
// - 适合国际化、本地化等场景

// 示例1:基本使用
function myTag(strings, ...values) {
  console.log('字符串数组:', strings);
  console.log('值数组:', values);
  
  let result = '';
  for (let i = 0; i < strings.length; i++) {
    result += strings[i];
    if (i < values.length) {
      result += `[${values[i]}]`;
    }
  }
  
  return result;
}

const name = '张三';
const age = 28;
const result = myTag`你好,我是${name},今年${age}岁。`;
console.log('标签函数结果:', result);

// 示例2:嵌套模板字符串
function outerTag(strings, ...values) {
  return `OUTER: ${strings[0]}${values[0]}${strings[1]}`;
}

function innerTag(strings, ...values) {
  return `INNER: ${strings[0]}${values[0]}${strings[1]}`;
}

const nestedResult = outerTag`外部模板${innerTag`内部模板${name}`}结束`;
console.log('嵌套标签结果:', nestedResult);

// 示例3:实际应用场景 - 国际化
const i18n = {
  en: {
    greeting: 'Hello, {name}! You are {age} years old.'
  },
  zh: {
    greeting: '你好,{name}!你今年{age}岁。'
  }
};

function translate(locale, strings, ...values) {
  const key = strings.join('{value}');
  let translation = i18n[locale][key] || strings.join('{value}');
  
  // 替换占位符
  values.forEach((value, index) => {
    translation = translation.replace(`{${Object.keys(i18n[locale])[index]}}`, value);
  });
  
  return translation;
}

// 使用标签函数进行国际化
const greetingEn = translate.bind(null, 'en');
const greetingZh = translate.bind(null, 'zh');

console.log(greetingEn`greeting`(name, age)); // 输出: Hello, 张三! You are 28 years old.
console.log(greetingZh`greeting`(name, age)); // 输出: 你好,张三!你今年28岁。

// ===============================
// 8. 类的静态块 (Static Blocks)
// ===============================

// 语法:
// class 类名 {
//   static {
//     // 静态块代码
//   }
// }

// 使用场景:
// - 类的静态初始化逻辑
// - 复杂的静态属性初始化
// - 静态属性之间的依赖关系
// - 适合需要在类加载时执行的初始化代码

// 示例1:基本使用
class Config {
  static config = null;
  
  // 静态块
  static {
    // 复杂的静态初始化逻辑
    const env = process.env.NODE_ENV || 'development';
    const baseUrl = env === 'production' ? 'https://api.example.com' : 'http://localhost:3000';
    
    this.config = {
      env,
      baseUrl,
      apiKey: 'secret-key-' + env
    };
  }
  
  static getConfig() {
    return this.config;
  }
}

console.log(Config.getConfig()); // 输出: { env: 'development', baseUrl: 'http://localhost:3000', apiKey: 'secret-key-development' }

// 示例2:多个静态块和静态属性的顺序
class MultipleStaticBlocks {
  static value1 = 1;
  
  static {
    this.value2 = this.value1 * 2;
  }
  
  static value3 = this.value2 * 2;
  
  static {
    this.value4 = this.value3 * 2;
  }
}

console.log('value1:', MultipleStaticBlocks.value1); // 输出: 1
console.log('value2:', MultipleStaticBlocks.value2); // 输出: 2
console.log('value3:', MultipleStaticBlocks.value3); // 输出: 4
console.log('value4:', MultipleStaticBlocks.value4); // 输出: 8

// 示例3:实际应用场景 - 数据库连接池初始化
class Database {
  static pool = null;
  
  static {
    // 初始化数据库连接池
    const { createPool } = require('mysql2/promise');
    
    this.pool = createPool({
      host: 'localhost',
      user: 'root',
      password: 'password',
      database: 'mydb',
      connectionLimit: 10
    });
    
    console.log('数据库连接池已初始化');
  }
  
  static async query(sql, params) {
    const [rows] = await this.pool.execute(sql, params);
    return rows;
  }
  
  static async close() {
    await this.pool.end();
    console.log('数据库连接池已关闭');
  }
}

// 类加载时会自动执行静态块初始化连接池
// 可以直接使用Database.query()进行查询

JavaScript Es14

复制代码
/*
ES14 (ECMAScript 2023) 新特性
官方公布的所有新特性详细说明和使用场景
ES2023 (ES14) 包含以下主要新特性:

1. Array.prototype.findLast() 和 Array.prototype.findLastIndex()
   - 从数组末尾开始查找元素
   - 找到符合条件的最后一个元素及其索引
   - 简化从后往前查找的操作

2. Array.prototype.toSorted()
   - 返回新的已排序数组,原数组不变
   - 保持数据不可变性
   - 适合函数式编程风格

3. Array.prototype.toReversed()
   - 返回新的反转数组,原数组不变
   - 保持数据不可变性
   - 适合函数式编程风格

4. Array.prototype.with()
   - 返回新数组,替换指定索引的元素
   - 保持数据不可变性
   - 适合更新数组中某个元素

5. Object.groupBy() 和 Map.groupBy()
   - 将数组按指定条件分组
   - Object.groupBy() 返回对象,键为字符串
   - Map.groupBy() 返回Map,键可以是任意类型
   - 适合数据分组、统计、分类

6. Symbol.metadataKey
   - 用于装饰器元数据的存储
   - 支持TC39装饰器提案
   - 适合框架和库开发

这些特性进一步增强了JavaScript的数组操作能力,提供了更多保持数据不可变性的方法,同时简化了数据分组和装饰器元数据处理。这些特性提高了代码的可读性、可维护性和开发效率,特别是在函数式编程和数据处理场景中。
*/


// ===============================
// 1. Array.prototype.findLast() 和 Array.prototype.findLastIndex() 方法
// ===============================

// 语法:
// array.findLast(callback(element, index, array), thisArg)
// array.findLastIndex(callback(element, index, array), thisArg)

// 使用场景:
// - 从数组末尾开始查找元素
// - 找到符合条件的最后一个元素
// - 获取符合条件的最后一个元素的索引
// - 适合需要从后往前查找的场景,如日志分析、最近记录等

// 示例1:findLast() 基本使用
const numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];

// 从数组末尾开始查找第一个大于3的元素
const lastGreaterThan3 = numbers.findLast(num => num > 3);
console.log(`最后一个大于3的元素:${lastGreaterThan3}`); // 输出: 4

// 传统方式:需要反转数组或从后往前遍历
const traditionalLastGreaterThan3 = [...numbers].reverse().find(num => num > 3);
console.log(`传统方式查找结果:${traditionalLastGreaterThan3}`); // 输出: 4

// 示例2:findLastIndex() 基本使用
const lastGreaterThan3Index = numbers.findLastIndex(num => num > 3);
console.log(`最后一个大于3的元素索引:${lastGreaterThan3Index}`); // 输出: 5

// 传统方式:从后往前遍历
let traditionalIndex = -1;
for (let i = numbers.length - 1; i >= 0; i--) {
  if (numbers[i] > 3) {
    traditionalIndex = i;
    break;
  }
}
console.log(`传统方式查找索引:${traditionalIndex}`); // 输出: 5

// 示例3:使用对象数组
const users = [
  { id: 1, name: '张三', active: false },
  { id: 2, name: '李四', active: true },
  { id: 3, name: '王五', active: false },
  { id: 4, name: '赵六', active: true }
];

// 查找最后一个活跃用户
const lastActiveUser = users.findLast(user => user.active);
console.log(`最后一个活跃用户:`, lastActiveUser); // 输出: { id: 4, name: '赵六', active: true }

// 查找最后一个活跃用户的索引
const lastActiveIndex = users.findLastIndex(user => user.active);
console.log(`最后一个活跃用户索引:${lastActiveIndex}`); // 输出: 3

// 示例4:实际应用场景 - 日志分析
const logs = [
  { timestamp: 1680000000, level: 'info', message: '系统启动' },
  { timestamp: 1680000100, level: 'error', message: '数据库连接失败' },
  { timestamp: 1680000200, level: 'warn', message: '内存使用率过高' },
  { timestamp: 1680000300, level: 'error', message: 'API请求超时' },
  { timestamp: 1680000400, level: 'info', message: '系统正常运行' }
];

// 查找最后一个错误日志
const lastErrorLog = logs.findLast(log => log.level === 'error');
console.log(`最后一个错误日志:`, lastErrorLog);

// ===============================
// 2. Array.prototype.toSorted() 方法
// ===============================

// 语法:
// array.toSorted(compareFunction)
// 返回一个新的已排序数组,原数组不变

// 使用场景:
// - 对数组进行排序,不修改原数组
// - 函数式编程风格,保持数据不可变性
// - 适合需要保留原始数组的场景
// - 链式调用中使用

// 示例1:基本使用
const originalArray = [3, 1, 4, 1, 5, 9, 2, 6];

// toSorted() 返回新数组,原数组不变
const sortedArray = originalArray.toSorted();
console.log(`原数组:${originalArray}`); // 输出: 3,1,4,1,5,9,2,6
console.log(`排序后数组:${sortedArray}`); // 输出: 1,1,2,3,4,5,6,9

// 与sort()方法比较(sort()会修改原数组)
const mutableArray = [3, 1, 4, 1, 5];
const sortedMutableArray = mutableArray.sort();
console.log(`sort()原数组:${mutableArray}`); // 输出: 1,1,3,4,5(原数组已修改)
console.log(`sort()返回值:${sortedMutableArray}`); // 输出: 1,1,3,4,5

// 示例2:使用比较函数
const numbersToSort = [10, 5, 8, 1, 7];

// 升序排序
const ascSorted = numbersToSort.toSorted((a, b) => a - b);
console.log(`升序排序:${ascSorted}`); // 输出: 1,5,7,8,10

// 降序排序
const descSorted = numbersToSort.toSorted((a, b) => b - a);
console.log(`降序排序:${descSorted}`); // 输出: 10,8,7,5,1

// 原数组仍保持不变
console.log(`原数组:${numbersToSort}`); // 输出: 10,5,8,1,7

// 示例3:对对象数组排序
const products = [
  { name: '手机', price: 5999 },
  { name: '笔记本电脑', price: 9999 },
  { name: '平板电脑', price: 3999 },
  { name: '智能手表', price: 1999 }
];

// 按价格升序排序
const productsByPriceAsc = products.toSorted((a, b) => a.price - b.price);
console.log('按价格升序排序:', productsByPriceAsc);

// 按价格降序排序
const productsByPriceDesc = products.toSorted((a, b) => b.price - a.price);
console.log('按价格降序排序:', productsByPriceDesc);

// 示例4:链式调用
const data = [5, 3, 8, 1, 2];
const result = data
  .filter(num => num > 2)
  .toSorted()
  .map(num => num * 2);
console.log('链式调用结果:', result); // 输出: [6, 10, 16]

// ===============================
// 3. Array.prototype.toReversed() 方法
// ===============================

// 语法:
// array.toReversed()
// 返回一个新的反转数组,原数组不变

// 使用场景:
// - 反转数组,不修改原数组
// - 函数式编程风格,保持数据不可变性
// - 适合需要保留原始数组顺序的场景
// - 链式调用中使用

// 示例1:基本使用
const original = [1, 2, 3, 4, 5];

// toReversed() 返回新数组,原数组不变
const reversed = original.toReversed();
console.log(`原数组:${original}`); // 输出: 1,2,3,4,5
console.log(`反转后数组:${reversed}`); // 输出: 5,4,3,2,1

// 与reverse()方法比较(reverse()会修改原数组)
const mutable = [1, 2, 3];
const reversedMutable = mutable.reverse();
console.log(`reverse()原数组:${mutable}`); // 输出: 3,2,1(原数组已修改)
console.log(`reverse()返回值:${reversedMutable}`); // 输出: 3,2,1

// 示例2:对象数组反转
const items = [
  { id: 1, name: '第一项' },
  { id: 2, name: '第二项' },
  { id: 3, name: '第三项' }
];

const reversedItems = items.toReversed();
console.log('原对象数组:', items);
console.log('反转后对象数组:', reversedItems);

// 示例3:链式调用
const chainData = [1, 2, 3, 4, 5];
const chainResult = chainData
  .filter(num => num % 2 === 0)
  .toReversed()
  .map(num => num * 3);
console.log('链式调用结果:', chainResult); // 输出: [12, 6]

// ===============================
// 4. Array.prototype.with() 方法
// ===============================

// 语法:
// array.with(index, value)
// 返回一个新数组,指定索引处的元素被替换为新值,原数组不变

// 使用场景:
// - 替换数组中指定索引的元素,不修改原数组
// - 函数式编程风格,保持数据不可变性
// - 适合需要更新数组中某个元素的场景
// - 链式调用中使用

// 示例1:基本使用
const originalWith = [1, 2, 3, 4, 5];

// with() 返回新数组,原数组不变
const newArrayWith = originalWith.with(2, 10);
console.log(`原数组:${originalWith}`); // 输出: 1,2,3,4,5
console.log(`替换后数组:${newArrayWith}`); // 输出: 1,2,10,4,5

// 传统方式:需要创建副本并修改
const traditionalNewArray = [...originalWith];
traditionalNewArray[2] = 10;
console.log(`传统方式替换结果:${traditionalNewArray}`); // 输出: 1,2,10,4,5

// 示例2:使用负索引
const arrayWithNegative = [1, 2, 3, 4, 5];
const newArrayWithNegative = arrayWithNegative.with(-1, 100);
console.log(`原数组:${arrayWithNegative}`); // 输出: 1,2,3,4,5
console.log(`替换最后一个元素:${newArrayWithNegative}`); // 输出: 1,2,3,4,100

// 示例3:对象数组更新
const usersWith = [
  { id: 1, name: '张三', age: 28 },
  { id: 2, name: '李四', age: 30 },
  { id: 3, name: '王五', age: 25 }
];

// 更新索引为1的用户年龄
const updatedUsers = usersWith.with(1, { ...usersWith[1], age: 31 });
console.log('原用户数组:', usersWith);
console.log('更新后用户数组:', updatedUsers);
console.log('是否为同一数组:', usersWith === updatedUsers); // 输出: false

// 示例4:链式调用
const chainDataWith = [1, 2, 3, 4, 5];
const chainResultWith = chainDataWith
  .toSorted()
  .with(0, 10)
  .toReversed();
console.log('链式调用结果:', chainResultWith); // 输出: [5, 4, 3, 2, 10]

// ===============================
// 5. Object.groupBy() 和 Map.groupBy() 方法
// ===============================

// 语法:
// Object.groupBy(items, callback(element, index, array))
// Map.groupBy(items, callback(element, index, array))

// 使用场景:
// - 将数组按指定条件分组
// - Object.groupBy() 返回对象,键为分组条件,值为分组后的数组
// - Map.groupBy() 返回Map,键可以是任意类型,值为分组后的数组
// - 适合数据分组、统计、分类等场景

// 示例1:Object.groupBy() 基本使用
const people = [
  { name: '张三', age: 28, gender: 'male' },
  { name: '李四', age: 30, gender: 'female' },
  { name: '王五', age: 25, gender: 'male' },
  { name: '赵六', age: 35, gender: 'female' },
  { name: '孙七', age: 22, gender: 'male' }
];

// 按性别分组
const groupedByGender = Object.groupBy(people, person => person.gender);
console.log('按性别分组结果:', groupedByGender);
// 输出:
// {
//   male: [
//     { name: '张三', age: 28, gender: 'male' },
//     { name: '王五', age: 25, gender: 'male' },
//     { name: '孙七', age: 22, gender: 'male' }
//   ],
//   female: [
//     { name: '李四', age: 30, gender: 'female' },
//     { name: '赵六', age: 35, gender: 'female' }
//   ]
// }

// 示例2:按年龄范围分组
const groupedByAgeRange = Object.groupBy(people, person => {
  if (person.age < 25) return 'young';
  if (person.age < 30) return 'middle';
  return 'old';
});
console.log('按年龄范围分组结果:', groupedByAgeRange);

// 示例3:Map.groupBy() 基本使用
// 按年龄奇偶性分组,键为布尔值
const groupedByAgeParity = Map.groupBy(people, person => person.age % 2 === 0);
console.log('按年龄奇偶性分组结果(Map):');
for (const [key, value] of groupedByAgeParity) {
  console.log(`${key}: ${JSON.stringify(value)}`);
}

// 示例4:使用对象作为分组键(只有Map支持)
const transactions = [
  { id: 1, amount: 100, category: { id: 1, name: '食品' } },
  { id: 2, amount: 200, category: { id: 2, name: '交通' } },
  { id: 3, amount: 150, category: { id: 1, name: '食品' } },
  { id: 4, amount: 50, category: { id: 3, name: '娱乐' } },
  { id: 5, amount: 300, category: { id: 2, name: '交通' } }
];

// 使用category对象作为分组键
const groupedByCategory = Map.groupBy(transactions, transaction => transaction.category);
console.log('按分类对象分组结果:');
for (const [category, items] of groupedByCategory) {
  console.log(`${category.name}:${items.length}笔交易,总金额${items.reduce((sum, item) => sum + item.amount, 0)}`);
}

// 示例5:实际应用场景 - 统计销售数据
const sales = [
  { product: '手机', region: '华东', amount: 5000 },
  { product: '笔记本电脑', region: '华南', amount: 8000 },
  { product: '手机', region: '华北', amount: 6000 },
  { product: '平板电脑', region: '华东', amount: 3000 },
  { product: '手机', region: '华南', amount: 7000 },
  { product: '笔记本电脑', region: '华北', amount: 9000 }
];

// 按产品分组
const salesByProduct = Object.groupBy(sales, sale => sale.product);
console.log('按产品分组销售数据:');
for (const [product, items] of Object.entries(salesByProduct)) {
  const totalAmount = items.reduce((sum, item) => sum + item.amount, 0);
  console.log(`${product}:${items.length}笔销售,总金额${totalAmount}`);
}

// 按地区分组
const salesByRegion = Object.groupBy(sales, sale => sale.region);
console.log('按地区分组销售数据:');
for (const [region, items] of Object.entries(salesByRegion)) {
  const totalAmount = items.reduce((sum, item) => sum + item.amount, 0);
  console.log(`${region}:${items.length}笔销售,总金额${totalAmount}`);
}

// ===============================
// 6. Symbol.metadataKey(装饰器元数据)
// ===============================

// 语法:
// Symbol.metadataKey

// 使用场景:
// - 用于装饰器元数据的存储
// - 支持TC39装饰器提案
// - 适合需要在类、方法、属性上存储元数据的场景
// - 用于框架和库的开发

// 示例1:基本使用
// 注意:装饰器目前需要在支持的环境中使用,如TypeScript或启用实验性装饰器的JavaScript引擎
/*
function log(target, context) {
  // 存储元数据
  const metadata = context.metadata[Symbol.metadataKey] || [];
  metadata.push({ kind: context.kind, name: context.name });
  context.metadata[Symbol.metadataKey] = metadata;
  
  return target;
}

@log
class MyClass {
  @log
  myMethod() {
    // 方法体
  }
}

// 获取元数据
const metadata = MyClass[Symbol.metadataKey];
console.log('类元数据:', metadata);
*/

// 示例2:自定义装饰器使用元数据
/*
function deprecated(reason) {
  return function(target, context) {
    // 存储废弃信息作为元数据
    const metadata = context.metadata[Symbol.metadataKey] || [];
    metadata.push({ deprecated: true, reason });
    context.metadata[Symbol.metadataKey] = metadata;
    
    // 在开发环境中添加警告
    if (context.kind === 'method') {
      return function(...args) {
        console.warn(`${context.name}方法已废弃:${reason}`);
        return target.apply(this, args);
      };
    }
    
    return target;
  };
}

class MyService {
  @deprecated('请使用newMethod替代')
  oldMethod() {
    return '旧方法';
  }
  
  newMethod() {
    return '新方法';
  }
}

const service = new MyService();
service.oldMethod(); // 输出警告:oldMethod方法已废弃:请使用newMethod替代
*/

JavaScript Es15

复制代码
/* 
ES15 (ECMAScript 2024) 新特性
发布年份:2024年6月
ES2024 (ES15) 包含以下主要新特性:
1. Promise.withResolvers()
   - 简化 Promise 创建,外部控制 resolve/reject
   - 提高代码可读性
   - 发布年份:2024

2. String.prototype.isWellFormed()
   - 检查字符串是否包含格式良好的 Unicode
   - 检测无效 UTF-16 代理对
   - 发布年份:2024

3. String.prototype.toWellFormed()
   - 将无效字符串转换为格式良好的字符串
   - 用 U+FFFD 替换无效代理对
   - 发布年份:2024

4. 正则表达式 v 标志
   - 启用 Unicode 集合语法
   - 支持集合操作(交集、并集、差集)
   - 增强 Unicode 支持
   - 发布年份:2024

5. ArrayBuffer.prototype.resize()
   - 动态调整 ArrayBuffer 大小
   - 提高内存使用效率
   - 发布年份:2024

6. ArrayBuffer.prototype.transfer()
   - 转移 ArrayBuffer 数据到新缓冲区
   - 避免复制,提高性能
   - 发布年份:2024

7. Atomics.waitAsync()
   - 异步等待共享内存值变化
   - 非阻塞操作,避免主线程阻塞
   - 适用于并发编程
   - 发布年份:2024

这些特性进一步增强了 JavaScript 语言的功能和性能,提高了开发者的编程体验和代码质量。
*/

// ===============================
// 1. Promise.withResolvers() 方法
// ===============================

// 语法:
// const { promise, resolve, reject } = Promise.withResolvers();

// 使用场景:
// - 简化手动创建 Promise 时管理 resolve 和 reject 的复杂性
// - 替代传统的 new Promise((resolve, reject) => { ... }) 模式
// - 适合需要在 Promise 外部控制 resolve/reject 的场景
// - 提高代码可读性和维护性

// 示例1:基本使用
console.log('=== Promise.withResolvers() 基本使用 ===');
const { promise, resolve, reject } = Promise.withResolvers();

promise.then(result => {
  console.log(`Promise 已解决:${result}`);
}).catch(error => {
  console.error(`Promise 已拒绝:${error}`);
});

// 在外部控制 Promise 的状态
setTimeout(() => {
  resolve('外部解决 Promise');
}, 1000);

// 示例2:替代传统 Promise 创建方式
console.log('\n=== Promise.withResolvers() 与传统方式对比 ===');

// 传统方式
const traditionalPromise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('传统方式解决'), 500);
});

// 使用 withResolvers()
const { promise: newPromise, resolve: newResolve } = Promise.withResolvers();
setTimeout(() => newResolve('withResolvers() 方式解决'), 500);

// 比较两种方式的结果
Promise.all([traditionalPromise, newPromise]).then(results => {
  console.log(`传统方式结果:${results[0]}`);
  console.log(`withResolvers() 结果:${results[1]}`);
});

// 示例3:实际应用场景 - 超时控制
console.log('\n=== Promise.withResolvers() 实际应用:超时控制 ===');

function withTimeout(promise, ms) {
  const { promise: timeoutPromise, reject: timeoutReject } = Promise.withResolvers();
  const timeoutId = setTimeout(() => timeoutReject(new Error('操作超时')), ms);
  
  return Promise.race([
    promise,
    timeoutPromise
  ]).finally(() => clearTimeout(timeoutId));
}

// 使用示例
const longRunningPromise = new Promise(resolve => {
  setTimeout(() => resolve('长时间操作完成'), 2000);
});

// 超时时间设为1000ms
withTimeout(longRunningPromise, 1000)
  .then(result => console.log(result))
  .catch(error => console.error(error.message));

// ===============================
// 2. String.prototype.isWellFormed() 方法
// ===============================

// 语法:
// string.isWellFormed()

// 使用场景:
// - 检查字符串是否包含格式良好的 Unicode
// - 检测是否有无效的 UTF-16 代理对
// - 适合处理来自外部的字符串数据
// - 用于数据验证和清理

// 示例1:基本使用
console.log('\n=== String.prototype.isWellFormed() 基本使用 ===');

// 格式良好的字符串
const wellFormed = 'Hello, World! 👋';
console.log(`${wellFormed} 是格式良好的:${wellFormed.isWellFormed()}`); // 输出: true

// 包含无效代理对的字符串
const badString = 'Hello, \uD800 World!'; // 无效的 UTF-16 代理对
console.log(`${badString} 是格式良好的:${badString.isWellFormed()}`); // 输出: false

// ===============================
// 3. String.prototype.toWellFormed() 方法
// ===============================

// 语法:
// string.toWellFormed()

// 使用场景:
// - 将包含无效 UTF-16 代理对的字符串转换为格式良好的字符串
// - 用 Unicode 替换字符 (U+FFFD) 替换无效代理对
// - 适合清理和修复外部字符串数据
// - 用于确保字符串可以安全处理

// 示例1:基本使用
console.log('\n=== String.prototype.toWellFormed() 基本使用 ===');

// 包含无效代理对的字符串
const malformedString = 'Hello, \uD800 \uDC00 World! \uD800';
console.log(`原始字符串:${malformedString}`);
console.log(`是否格式良好:${malformedString.isWellFormed()}`); // 输出: false

// 转换为格式良好的字符串
const fixedString = malformedString.toWellFormed();
console.log(`修复后的字符串:${fixedString}`);
console.log(`是否格式良好:${fixedString.isWellFormed()}`); // 输出: true

// 示例2:实际应用场景 - 清理用户输入
console.log('\n=== String.prototype.toWellFormed() 实际应用:清理用户输入 ===');

function sanitizeInput(input) {
  // 移除无效字符并转换为格式良好的字符串
  return input.toWellFormed().trim();
}

// 使用示例
const userInput = '  用户输入包含无效字符:\uD800  \n';
const sanitizedInput = sanitizeInput(userInput);
console.log(`原始输入:${JSON.stringify(userInput)}`);
console.log(`清理后输入:${JSON.stringify(sanitizedInput)}`);
console.log(`是否格式良好:${sanitizedInput.isWellFormed()}`);

// ===============================
// 4. 正则表达式 v 标志(Unicode Sets)
// ===============================

// 语法:
// /pattern/v

// 使用场景:
// - 启用 Unicode 集合语法
// - 支持更强大的 Unicode 字符类
// - 允许集合的交集、并集和差集
// - 提供更好的 Unicode 支持

// 示例1:基本使用
console.log('\n=== 正则表达式 v 标志基本使用 ===');

// 使用 v 标志创建正则表达式
const regexV = /^[\p{Script=Greek}]+$/v;
console.log(`"Αλφαβητο" 是否匹配希腊字母:${regexV.test('Αλφαβητο')}`); // 输出: true
console.log(`"Hello" 是否匹配希腊字母:${regexV.test('Hello')}`); // 输出: false

// 示例2:Unicode 集合操作
console.log('\n=== 正则表达式 v 标志:Unicode 集合操作 ===');

// 并集操作:匹配元音字母 (a, e, i, o, u) 或数字
const unionRegex = /^[aeiou\d]+$/v;
console.log(`"aeiou" 是否匹配元音或数字:${unionRegex.test('aeiou')}`); // 输出: true
console.log(`"12345" 是否匹配元音或数字:${unionRegex.test('12345')}`); // 输出: true
console.log(`"abc123" 是否匹配元音或数字:${unionRegex.test('abc123')}`); // 输出: false

// 示例3:与 u 标志的对比
console.log('\n=== 正则表达式 v 标志与 u 标志对比 ===');

const regexU = /^\p{L}+$/u;
const regexV = /^\p{L}+$/v;

console.log(`使用 u 标志匹配 "Hello":${regexU.test('Hello')}`); // 输出: true
console.log(`使用 v 标志匹配 "Hello":${regexV.test('Hello')}`); // 输出: true

// v 标志支持更高级的 Unicode 特性
const regexVAdvanced = /^[\p{Letter}&&[^\p{Script=Latin}]]+$/v;
console.log(`"Αλφαβητο" 是否匹配非拉丁字母:${regexVAdvanced.test('Αλφαβητο')}`); // 输出: true
console.log(`"Hello" 是否匹配非拉丁字母:${regexVAdvanced.test('Hello')}`); // 输出: false

// ===============================
// 5. ArrayBuffer.prototype.resize() 方法
// ===============================

// 语法:
// arrayBuffer.resize(newLength)

// 使用场景:
// - 调整 ArrayBuffer 的大小
// - 适合需要动态调整缓冲区大小的场景
// - 用于处理不确定大小的数据
// - 提高内存使用效率

// 示例1:基本使用
console.log('\n=== ArrayBuffer.prototype.resize() 基本使用 ===');

// 创建一个可调整大小的 ArrayBuffer
const buffer = new ArrayBuffer(8, { maxByteLength: 16 });
console.log(`初始缓冲区大小:${buffer.byteLength} 字节`); // 输出: 8

// 调整大小为 12 字节
buffer.resize(12);
console.log(`调整后缓冲区大小:${buffer.byteLength} 字节`); // 输出: 12

// 调整大小为 16 字节(最大值)
buffer.resize(16);
console.log(`再次调整后缓冲区大小:${buffer.byteLength} 字节`); // 输出: 16

// 示例2:写入和读取数据
console.log('\n=== ArrayBuffer.prototype.resize() 读写数据 ===');

const dataBuffer = new ArrayBuffer(4, { maxByteLength: 16 });
const view = new Uint32Array(dataBuffer);

// 写入初始数据
view[0] = 0x12345678;
console.log(`初始数据:0x${view[0].toString(16)}`); // 输出: 0x12345678

// 调整大小并写入更多数据
dataBuffer.resize(8);
const view8 = new Uint32Array(dataBuffer);
view8[1] = 0x87654321;
console.log(`调整后数据[0]:0x${view8[0].toString(16)}`); // 输出: 0x12345678
console.log(`调整后数据[1]:0x${view8[1].toString(16)}`); // 输出: 0x87654321

// ===============================
// 6. ArrayBuffer.prototype.transfer() 方法
// ===============================

// 语法:
// arrayBuffer.transfer(newByteLength)
// arrayBuffer.transfer() // 使用原大小

// 使用场景:
// - 将 ArrayBuffer 的数据转移到新的 ArrayBuffer
// - 避免复制大型缓冲区,提高性能
// - 适合需要转移所有权的场景
// - 用于优化内存使用

// 示例1:基本使用
console.log('\n=== ArrayBuffer.prototype.transfer() 基本使用 ===');

const sourceBuffer = new ArrayBuffer(8);
const sourceView = new Uint32Array(sourceBuffer);
sourceView[0] = 0x11223344;
sourceView[1] = 0x55667788;

console.log(`源缓冲区大小:${sourceBuffer.byteLength} 字节`); // 输出: 8
console.log(`源数据[0]:0x${sourceView[0].toString(16)}`); // 输出: 0x11223344

// 转移数据到新缓冲区
const transferredBuffer = sourceBuffer.transfer(12); // 可以调整大小
console.log(`转移后源缓冲区大小:${sourceBuffer.byteLength} 字节`); // 输出: 0
console.log(`新缓冲区大小:${transferredBuffer.byteLength} 字节`); // 输出: 12

// 读取转移后的数据
const transferredView = new Uint32Array(transferredBuffer);
console.log(`新缓冲区数据[0]:0x${transferredView[0].toString(16)}`); // 输出: 0x11223344
console.log(`新缓冲区数据[1]:0x${transferredView[1].toString(16)}`); // 输出: 0x55667788

// 示例2:实际应用场景 - 数据传输优化
console.log('\n=== ArrayBuffer.prototype.transfer() 实际应用:数据传输优化 ===');

function processLargeData(data) {
  // 处理数据...
  console.log(`处理了 ${data.byteLength} 字节的数据`);
  
  // 转移数据,避免复制
  return data.transfer();
}

// 使用示例
const largeBuffer = new ArrayBuffer(1024 * 1024); // 1MB 缓冲区
console.log(`创建了 ${largeBuffer.byteLength} 字节的缓冲区`);

const processedBuffer = processLargeData(largeBuffer);
console.log(`处理后原始缓冲区大小:${largeBuffer.byteLength} 字节`);
console.log(`处理后新缓冲区大小:${processedBuffer.byteLength} 字节`);

// ===============================
// 7. Atomics.waitAsync() 方法
// ===============================

// 语法:
// Atomics.waitAsync(typedArray, index, value, timeout)

// 使用场景:
// - 异步等待共享内存位置的值变化
// - 避免阻塞主线程
// - 适合并发编程场景
// - 用于 Web Workers 之间的通信

// 示例1:基本使用(概念演示)
console.log('\n=== Atomics.waitAsync() 基本使用 ===');

// 创建一个共享的 ArrayBuffer
const sharedBuffer = new SharedArrayBuffer(4);
const sharedView = new Int32Array(sharedBuffer);

// 初始值设为 0
Atomics.store(sharedView, 0, 0);

// 异步等待值变化
const waitResult = Atomics.waitAsync(sharedView, 0, 0, 1000);

console.log(`等待状态:${waitResult.async ? '异步' : '同步'}`);

// 在另一个上下文(如 Worker)中修改值
setTimeout(() => {
  Atomics.store(sharedView, 0, 1);
  Atomics.notify(sharedView, 0);
  console.log('已修改共享内存的值并通知等待者');
}, 500);

// 处理等待结果
waitResult.value.then(result => {
  console.log(`等待结果:${result}`); // 输出: ok
}).catch(error => {
  console.error(`等待出错:${error}`);
});

// 示例2:实际应用场景 - 非阻塞等待
console.log('\n=== Atomics.waitAsync() 实际应用:非阻塞等待 ===');

// 模拟一个需要等待共享资源的场景
function waitForResource(resource, expectedValue, timeout) {
  return Atomics.waitAsync(resource, 0, expectedValue, timeout).value;
}

// 使用示例
const resourceBuffer = new SharedArrayBuffer(4);
const resourceView = new Int32Array(resourceBuffer);
Atomics.store(resourceView, 0, 0);

console.log('开始等待资源可用...');

// 非阻塞等待
waitForResource(resourceView, 0, 2000).then(result => {
  console.log(`资源等待结果:${result}`);
  if (result === 'ok') {
    console.log('资源已可用,开始处理...');
  } else {
    console.log('资源等待超时');
  }
});

// 模拟资源被释放
setTimeout(() => {
  Atomics.store(resourceView, 0, 1);
  Atomics.notify(resourceView, 0);
  console.log('资源已释放');
}, 1000);
相关推荐
jump_jump6 分钟前
基于 Squoosh WASM 的浏览器端图片转换库
前端·javascript·性能优化
阿珊和她的猫4 小时前
IIFE:JavaScript 中的立即调用函数表达式
开发语言·javascript·状态模式
智商偏低5 小时前
JSEncrypt
javascript
2501_944711436 小时前
构建 React Todo 应用:组件通信与状态管理的最佳实践
前端·javascript·react.js
困惑阿三6 小时前
2025 前端技术全景图:从“夯”到“拉”排行榜
前端·javascript·程序人生·react.js·vue·学习方法
苏瞳儿6 小时前
vue2与vue3的区别
前端·javascript·vue.js
weibkreuz8 小时前
收集表单数据@10
开发语言·前端·javascript
王林不想说话8 小时前
提升工作效率的Utils
前端·javascript·typescript
weixin_584121439 小时前
vue内i18n国际化移动端引入及使用
前端·javascript·vue.js
imkaifan9 小时前
bind函数--修改this指向,返回一个函数
开发语言·前端·javascript·bind函数