这种轻量级格式是网络上交换和存储结构化数据最常用的方式之一,在 API、配置文件、模拟数据集和应用设置中随处可见。
如果您需要在 JavaScript 中读取 JSON 文件内容,选择哪种方法主要取决于代码的运行环境。本指南将介绍 fetch API、FileReader、ES modules,以及 Node.js 中的 require() 和 fs 等工具。
理解 JavaScript 中的 JSON
JSON 全称为 JavaScript Object Notation,以键值对、数组、字符串、数字、布尔值和 null 值的形式存储信息。一个基本的 JSON 文件大致如下:
{
"name": "Mars",
"active": true,
"ports": [8000, 8001, 8002]
}
虽然这种格式看起来与普通的 JavaScript 对象相似,但两者并不完全相同。JSON 是一种基于文本的数据格式,语法规则严格:例如属性名必须使用双引号,且不支持注释或函数。
加载并解析 JSON 数据后,JavaScript 通常会将其转换为可在代码中直接使用的普通对象或数组。
如何在 JavaScript 中读取 JSON 文件
读取 JSON 文件的方法有多种,各自适用于不同的运行环境。
在浏览器中,fetch API 通常最适合读取网站提供的文件,而 FileReader 则适用于用户选择的本地文件。在基于模块的现代项目中,您可以直接导入数据;在 Node.js 中,require() 和 fs 模块是常见选择。
A. 使用 Fetch API(浏览器端)
Fetch API 是从同一网站或公共链接获取 JSON 数据最简便的方法。它通过发起 HTTP 请求来执行此操作,并返回一个包含 Response 对象的 Promise。利用该 Response 对象,你可以通过调用 `response.json()` 来获取数据。
假设您的项目包含以下结构:
project/
├── index.html
├── app.js
└── users.json
您的 JavaScript 文件可以这样加载 users.json:
async function loadUsers() {
try {
const response = await fetch('./users.json');
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Could not load JSON:', error);
}
}
loadUsers();
Fetch API 方法首先会请求 JSON 文件。通过 `response.ok` 进行检查,可以捕获诸如 404 或 500 之类的 HTTP 错误,因为 `fetch()` 并不会自动拒绝所有不成功的 HTTP 状态。随后,`.json()` 会读取响应主体,并将响应中的 JSON 内容解析为可用的 JSON 数据。
如果数据是从其他域名获取的,CORS 会阻止这一操作。服务器必须通过正确的 CORS 请求头授权该来源域名,仅修改客户端代码无法绕过 CORS 限制。
作为兜底处理,应捕获错误并展示缓存内容、空状态或友好提示,而不是让页面直接报错。
B. 使用 FileReader API(浏览器端,读取本地文件)
fetch API 无法自由打开用户电脑上的任意文件。如果需要让用户选择本地 JSON 文件,请使用 <input type="file"> 元素配合 FileReader API。
您的 HTML 文件可以包含:
<input type="file" id="jsonFile" accept=".json">
<pre id="output"></pre>
然后使用以下 JavaScript 代码:
const input = document.getElementById('jsonFile');
const output = document.getElementById('output');
input.addEventListener('change', () => {
const file = input.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => {
try {
const data = JSON.parse(reader.result);
output.textContent = JSON.stringify(data, null, 2);
} catch (error) {
output.textContent = 'Invalid JSON file.';
}
};
reader.readAsText(file);
});
FileReader 会将用户选择的本地 JSON 文件以文本形式读取,随后 JSON.parse() 会将该字符串转换为 JavaScript 对象。
FileReader 仅能访问用户主动选择的文件,这有助于防止浏览器无限制地访问本地文件。其 readAsText() 方法会将整个文件加载到内存中,因此不适合处理体积很大的文件。
务必将 JSON 解析逻辑放入 try/catch 中:一个缺失的逗号、多余的末尾逗号,或损坏的引号,都可能导致整个 JSON 文件失效。
C. 使用 ES6 Modules 的 import(现代 JavaScript)
现代 JavaScript 模块也可以直接从 JSON 导入数据。在支持 JSON 模块的标准化环境中,当前语法使用了一个 import attribute:
import settings from './settings.json' with { type: 'json' };
console.log(settings);
在 Node.js 中,导入 JSON 模块需要加上 type: 'json' 这一属性。如果您的 JavaScript 文件使用 .js 扩展名,并希望 Node 将其视为 ES module,可以在 package.json 中加入以下内容:
{
"type": "module"
}
现代浏览器同样通过 import attribute 导入这些模块,此时 JSON 文件需以对应的 JSON MIME 类型提供。
Vite 或 Next.js 等工具可能允许通过其打包机制导入 JSON 文件,因此具体语法会因构建配置的不同而有所差异。
当 JSON 文件属于应用源代码的一部分、且无需在运行时发生变化时,这种方法非常方便。
D. 在 Node.js 中使用 require() 或 fs.readFile()
Node.js 提供了多种读取 JSON 文件的方式。在 CommonJS 项目中,require() 是最简洁的写法:
const fs = require('node:fs');
const text = fs.readFileSync('./config.json', 'utf8');
const config = JSON.parse(text);
console.log(config);
fs.readFileSync() 会阻塞事件循环,直至文件读取和解析过程完成。这在应用启动阶段或许可以接受,但其他情况下应优先选用异步代码。
const fs = require('node:fs');
fs.readFile('./users.json', 'utf8', (error, text) => {
if (error) {
console.error('Read error:', error);
return;
}
try {
const users = JSON.parse(text);
console.log(users);
} catch (error) {
console.error('Invalid JSON:', error);
}
});
当应用需要在不阻塞其他任务的前提下读取 JSON 文件时,应使用异步文件访问方式。
常见问题及排查方法
第一个常见问题是输入格式错误:即便是很小的语法失误,也可能导致解析失败,因此应对不熟悉来源的 JSON 数据进行校验,并在 JSON 解析操作周围妥善处理异常。
另一个常见问题是在获取数据或读取磁盘文件时,混用同步和异步代码。fetch API、response.json()、FileReader 和 fs.readFile() 都不会立即返回最终数据。如果在 Promise 或回调完成之前就试图使用其结果,代码可能会得到 undefined 值。
另外,很容易混淆数据字符串与已解析的对象。以下是字符串形式:
const raw = '{"country":"US"}';
以下是已解析的数据:
const data = JSON.parse(raw);
console.log(data.country);
最后,处理体积较大或嵌套层级很深的文件时需格外小心。将整个 JSON 文件一次性加载到内存中可能开销很大。对于大型数据集,可以考虑使用流式读取、分页、拆分数据集,或改为存储在数据库中。
实际示例与使用场景
一个适合初学者练习的简单项目,是从 JSON 文件中加载商品卡片。例如在 products.json 文件中,内容可能如下:
[
{ "name": "Residential Proxies", "type": "Rotating" },
{ "name": "ISP Proxies", "type": "Static" }
]
您可以使用 fetch API 获取该数据并构建界面:
async function showProducts() {
const response = await fetch('./products.json');
const products = await response.json();
const container = document.getElementById('products');
products.forEach(product => {
const card = document.createElement('div');
card.textContent = `${product.name} - ${product.type}`;
container.appendChild(card);
});
}
showProducts();
同样的方法也适用于下拉选项、价格卡片、语言列表、模拟 API 结果,以及其他由 JSON 驱动的界面。它能让内容与渲染代码相分离,使更新操作更加简便。
如果数据集非常小且保持不变,您也可以在脚本中直接使用内联 JSON;但如果多个页面或脚本需要共用同一份数据,使用外部 JSON 文件会更合适。
如果想要实际演示效果,可以将这些示例粘贴到 CodePen、StackBlitz 或一个小型 GitHub 仓库中,并通过本地开发服务器提供文件访问。请避免仅通过 file:// 方式打开页面,因为浏览器的安全规则可能会干扰从本地文件获取数据。
结语
并不存在一种在所有场景下都完美适用的 JSON 文件解析方法。对于通过 HTTP 提供的 JSON 文件,可以使用 fetch API;对于用户选择的 JSON 文件,则适合使用 FileReader。
对于基于模块的应用,如果 JSON 数据已随应用一起打包,直接导入数据会很方便。在 Node.js 中,require() 很适合基础的 CommonJS 配置解析,而 fs.readFile() 则更适合异步文件读取场景。
对初学者而言,最容易上手的方式是在浏览器中使用 fetch API、在 Node.js 中使用 fs.readFile()。一旦理解了解析发生的时机,以及代码是同步还是异步执行,处理这种格式就会变得清晰可控得多。