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);
相关推荐
熊猫_豆豆2 小时前
一个模拟四轴飞行器在随机气流扰动下悬停飞行的交互式3D仿真网页,包含飞行器建模与PID控制算法
javascript·3d·html·四轴无人机模拟飞行
来恩10033 小时前
jQuery选择器
前端·javascript·jquery
前端繁华如梦3 小时前
树上挂苹果还是挂玻璃球?Three.js 程序化果实的完整实现指南
前端·javascript
CDwenhuohuo4 小时前
优惠券组件直接用 uview plus
前端·javascript·vue.js
川冰ICE4 小时前
TypeScript装饰器与元编程实战
前端·javascript·typescript
AI砖家5 小时前
Vue3组件传参大全,各种传参方式的对比
前端·javascript·vue.js
希望永不加班5 小时前
var局部变量类型推断的利弊
java·服务器·前端·javascript·html
threelab5 小时前
Three.js 3D 地图可视化 | 三维可视化 / AI 提示词
前端·javascript·人工智能·3d·着色器
失眠的咕噜6 小时前
PDA 安卓设备上传多张图片
android·前端·javascript
掰头战士6 小时前
深入了解JS原型及原型继承链机制
javascript