You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在浏览器中简便提取JavaScript ES模块的所有导出名称?

取巧提取ESM导出名称的可行思路

以下两种方法无需实现完整词法分析或执行原代码业务逻辑,能覆盖你提到的解构赋值、多变量声明场景(注:无法100%覆盖所有极端语法,但满足大部分实用需求):

方法一:增强版正则表达式(轻量易实现)

针对目标场景优化正则,分模式匹配导出,步骤如下:

  1. 先移除代码中的单行/多行注释,避免干扰匹配
  2. 分别匹配基础导出、对象解构导出、数组解构导出、多变量声明四种模式
  3. 对每种模式的匹配结果做解析,提取最终导出名称

示例代码

function extractExportNames(esmCode) {
  // 移除所有注释
  const cleanCode = esmCode
    .replace(/\/\/.*/g, '')
    .replace(/\/\*[\s\S]*?\*\//g, '');
  
  const exportNames = new Set();

  // 匹配基础导出:export const answer = 42
  const basicExportRegex = /export\s+(?:const|let|var)\s+([a-zA-Z_$][\w$]*)\s*=/g;
  let match;
  while ((match = basicExportRegex.exec(cleanCode)) !== null) {
    exportNames.add(match[1]);
  }

  // 匹配对象解构导出:export const { name1, name2: bar } = o
  const objDestructRegex = /export\s+(?:const|let|var)\s+\{\s*([^}]+)\s*\}/g;
  while ((match = objDestructRegex.exec(cleanCode)) !== null) {
    match[1].split(',').forEach(item => {
      const [rawName, alias] = item.trim().split(':').map(s => s.trim());
      exportNames.add(alias || rawName);
    });
  }

  // 匹配数组解构导出:export const [ name1, name2 ] = array
  const arrDestructRegex = /export\s+(?:const|let|var)\s+\[\s*([^\]]+)\s*\]/g;
  while ((match = arrDestructRegex.exec(cleanCode)) !== null) {
    match[1].split(',').forEach(item => {
      // 处理数组解构中的默认值,比如 [name = 123]
      const name = item.trim().split('=')[0].trim();
      exportNames.add(name);
    });
  }

  // 匹配多变量声明:export const name1 = 1, name2 = 2
  const multiVarRegex = /export\s+(?:const|let|var)\s+([^;]+)/g;
  while ((match = multiVarRegex.exec(cleanCode)) !== null) {
    match[1].split(',').forEach(item => {
      const name = item.trim().split('=')[0].trim();
      if (/^[a-zA-Z_$][\w$]*$/.test(name)) {
        exportNames.add(name);
      }
    });
  }

  return Array.from(exportNames);
}

// 测试用例
const testESM = `
export const answer = 42;
// 解构赋值
export const { name1, name2: bar } = o;
export const [ name1, name2 ] = array;

// 同时声明与赋值
export const name1 = 1, name2 = 2/*, … */;
`;
console.log(extractExportNames(testESM)); // 输出: ["answer", "name1", "bar", "name2"]

局限:无法处理嵌套解构(如export const { obj: { nested } } = o)、带复杂表达式的极端声明场景。

方法二:借浏览器引擎解析(覆盖更多语法)

利用JavaScript引擎的语法解析能力,通过包裹代码避免执行原业务逻辑,直接提取导出名称:

  1. 将ESM代码中的export关键字替换为普通变量声明
  2. 替换所有赋值表达式为= undefined,彻底消除执行副作用
  3. 用Function构造函数执行包裹后的代码,返回变量名称列表

示例代码

function extractViaEngineParse(esmCode) {
  try {
    // 替换export为普通声明,替换赋值为undefined避免副作用
    const wrappedCode = esmCode
      .replace(/export\s+(const|let|var)\s+/g, '$1 ')
      .replace(/=\s*.+?(?=;|,|\n)/g, '= undefined');
    
    // 构造函数返回所有声明的变量名
    const getExports = new Function(`
      ${wrappedCode}
      const vars = {};
      ${wrappedCode.split(';').filter(line => line.trim()).map(line => {
        const varName = line.trim().split(/\s|=/)[1];
        return `vars.${varName} = true;`;
      }).join('\n')}
      return Object.keys(vars);
    `);
    return getExports();
  } catch (err) {
    console.error('解析失败:', err);
    return [];
  }
}

优势:能处理嵌套解构、复杂变量声明等更多场景,依赖浏览器原生解析能力,无需自己维护正则规则;
注意:若原代码存在语法错误,会抛出异常,需额外捕获处理。

内容的提问来源于stack exchange,提问作者vanilla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:45:14