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

JavaScript导出JSON为Excel文件时触发r.forEach非函数类型错误

问题说明

使用JavaScript搭配xlsx库实现JSON数据导出Excel功能时,点击导出按钮触发以下报错,功能无法正常运行:

Uncaught TypeError: r.forEach is not a function at rb (xlsx.full.min.js:23:18346) at Object.tb [as json_to_sheet] (xlsx.full.min.js:23:19000) at downloadAsExcel (mains.js:61:32) at HTMLButtonElement.onclick (prepare.php:16:83)

涉及的现有代码和依赖如下:

涉及文件代码

prepear.php(报错信息中显示为prepare.php,存在文件名拼写不一致问题)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        
        <title>Document</title>
        
        <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.2/xlsx.full.min.js"></script>
        <script src='https://unpkg.com/tesseract.js@v2.1.0/dist/tesseract.min.js'></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> 
        <!-- <script src='excelexportjs.js'></script> -->
        <script src='main.js'></script>
        <script src="filesaver.js"></script>
        
        <div class="container mt-5 ">
            <pre id="json"></pre>
            <button class="btn btn-primary" onclick="downloadAsExcel(json.innerHTML)">download excel</button>
        </div>
    </head>
    <body>
    </body>
</html>

main.js(报错信息中显示为mains.js,存在文件名拼写不一致问题,且代码未写完)

async function readFile(fileName)
{
    console.log({
        fileName
    }); 
        
    return await Tesseract.recognize(fileName, 'ara', {
        logger: m => console.log(m)
    }); // fake it ...
}

async function parseDataFromTextAndPropertyNames(text, propertyNames)
{
    console.log({
        text, propertyNames
    });
        
    return propertyNames .reduce((table, key) => Object.assign(table, {
        [ key ]: RegExp(`${ key }\W+(\w+)`) .exec(text)?.[1] ?? '' }
    ), {});
}

async function writeParsedTextDataAsJSON(fileName, table)
{
    console.log({
        table
    });
        
    JSON.stringify({
        table
    }) // fake it ...
        
    return (await new Promise(resolve => setTimeout(() => {
        console.log({ fileName, json: JSON.stringify({ table }) });
        resolve({ success: true });
    }, 1500) ));

引入第三方依赖

  • xlsx 0.16.2版本
  • tesseract.js v2.1.0版本
  • jQuery 3.6.0版本
  • 本地filesaver.js脚本

根因分析

报错核心原因是XLSX.utils.json_to_sheet方法强制要求传入值为对象数组类型,方法内部会对传入的第一个参数调用forEach做行遍历,而现有代码直接传入<pre id="json">的innerHTML,属于字符串类型,字符串本身没有forEach方法,直接触发类型错误。
除此之外代码还存在3个附加问题:

  • 现有main.js中未实现downloadAsExcel方法,且文件名拼写和页面引用不一致,可能存在加载错误
  • 传入的innerHTML是JSON格式的纯文本,没有先通过JSON.parse()转换为可操作的JavaScript对象;就算完成解析,现有代码存储的JSON结构是{table: 数据数组}的嵌套对象,不是json_to_sheet要求的直接数组结构
  • HTML结构错误:包含按钮的container div被写在了<head>标签内部,正常DOM结构应该放在<body>标签内,可能导致元素加载异常

排查步骤
  1. 在downloadAsExcel方法第一行打印传入参数的类型和值,确认传入的是字符串而非目标数组
  2. 检查浏览器控制台的网络请求面板,确认main.js、filesaver.js没有404加载错误,文件名引用完全匹配
  3. 检查pre标签内写入的JSON结构,确认最终要导出的表格数据是标准对象数组格式,例:[{列名1:值1, 列名2:值2}, {列名1:值3, 列名2:值4}]
  4. 检查HTML结构,把head内的DOM元素移到body标签内部

修复方案
  1. 修正HTML结构错误,统一文件名拼写,调整按钮点击传参逻辑,修改后的页面代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.2/xlsx.full.min.js"></script>
    <script src='https://unpkg.com/tesseract.js@v2.1.0/dist/tesseract.min.js'></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> 
    <script src='main.js'></script>
    <script src="filesaver.js"></script>
</head>
<body>
    <div class="container mt-5 ">
        <pre id="json"></pre>
        <button class="btn btn-primary" onclick="handleDownload()">download excel</button>
    </div>
</body>
</html>
  1. 补全main.js中未写完的函数,新增downloadAsExcel方法,添加JSON解析、类型校验逻辑,修改后的完整main.js代码:
async function readFile(fileName)
{
    console.log({fileName}); 
    return await Tesseract.recognize(fileName, 'ara', {
        logger: m => console.log(m)
    });
}

async function parseDataFromTextAndPropertyNames(text, propertyNames)
{
    console.log({text, propertyNames});
    return propertyNames.reduce((table, key) => Object.assign(table, {
        [key]: RegExp(`${key}\W+(\w+)`).exec(text)?.[1] ?? '' }
    ), {});
}

async function writeParsedTextDataAsJSON(fileName, table)
{
    console.log({table});
    const jsonStr = JSON.stringify({table});
    // 把生成的JSON内容写入pre标签
    document.getElementById('json').textContent = jsonStr;
    return await new Promise(resolve => setTimeout(() => {
        console.log({ fileName, json: jsonStr });
        resolve({ success: true });
    }, 1500));
}

// 实现Excel导出方法
function downloadAsExcel(exportData) {
    // 强校验传入数据必须是数组
    if (!Array.isArray(exportData)) {
        throw new Error('导出数据必须为对象数组格式');
    }
    // 数组转工作表
    const worksheet = XLSX.utils.json_to_sheet(exportData);
    // 创建工作簿并挂载工作表
    const workbook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(workbook, worksheet, '导出数据');
    // 生成Excel文件二进制流
    const excelBuffer = XLSX.write(workbook, {bookType:'xlsx', type:'array'});
    // 转Blob触发下载
    const blob = new Blob([excelBuffer], {type:'application/octet-stream'});
    saveAs(blob, `导出数据_${new Date().getTime()}.xlsx`);
}

// 按钮点击处理逻辑
function handleDownload() {
    const jsonText = document.getElementById('json').textContent;
    try {
        // 把pre标签内的JSON字符串解析为JS对象
        const parsedData = JSON.parse(jsonText);
        // 取出嵌套的表格数组
        const tableData = parsedData.table;
        // 调用导出方法
        downloadAsExcel(tableData);
    } catch (err) {
        console.error('导出失败:', err);
        alert('数据解析失败,请检查JSON格式是否正确');
    }
}
  1. 验证逻辑:先调用writeParsedTextDataAsJSON写入测试数据到pre标签,再点击导出按钮即可正常生成Excel文件,不会再触发forEach类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 18:27:33