
本文详解 Node.js + Express 应用中因模板数据传递与变量名不一致导致的 ReferenceError: xxx is not defined 错误,重点解决 EJS 模板中访问未定义变量的问题,并提供可复现的修复方案与最佳实践。
本文详解 node.js + express 应用中因模板数据传递与变量名不一致导致的 `referenceerror: xxx is not defined` 错误,重点解决 ejs 模板中访问未定义变量的问题,并提供可复现的修复方案与最佳实践。
在使用 Express 搭配 EJS 渲染动态页面时,一个高频却易被忽视的错误是:模板中引用的变量名与 res.render() 传入的数据键名不匹配,从而触发 ReferenceError。正如你在 author.ejs 中遇到的报错:
ReferenceError: articles is not defined
at eval (eval at compile (...\node_modules\ejs\lib\ejs.js:662:12), <anonymous>:32:19)根本原因在于:你在路由中调用的是
res.render('author', { author: articles })——即把文章数组绑定到模板上下文的 author 属性上;
但在 author.ejs 模板中却尝试访问:
<% articles.forEach(article => { %>由于 articles 并未被传入(author 才是实际存在的变量),EJS 引擎自然抛出引用错误。
✅ 正确修复方式(二选一)
方案一:修改模板,匹配传入的变量名(推荐)
保持路由逻辑不变,仅调整 EJS 中的变量引用:
<!-- author.ejs -->
<% author.forEach(article => { %>
<div class="card mt-4">
<div class="card-body">
<h4 class="card-title"><%= article.title %></h4>
<div class="card-subtitle text-muted mb-2">
<%= article.createdAt.toLocaleDateString() %>
</div>
<div class="card-text mb-2"><%= article.subtitle || article.description %></div>
<!-- 注意:原始代码中用了 article.description,但示例数据无该字段,建议统一用 subtitle 或补充字段 -->
</div>
</div>
<% }) %>方案二:修改路由,统一使用语义化变量名
若希望模板中直接使用 articles,则需同步更新 res.render() 的数据对象:
// author.js(路由文件)
router.get('/home', (req, res) => {
const articles = [{
title: 'test article',
subtitle: 'test subtitle',
createdAt: new Date(),
lastModified: new Date()
}];
// ✅ 改为 { articles: articles },键名与模板引用一致
res.render('author', { articles });
});对应模板中即可安全使用:
<% articles.forEach(article => { %>
<!-- ... -->
<% }) %>⚠️ 关键注意事项
- 变量作用域严格限定在 res.render() 传入的对象内:EJS 模板无法访问路由函数内部的局部变量(如 articles 常量),只能访问你显式注入的属性。
- 命名一致性至关重要:建议采用“所见即所得”原则——模板中怎么写,res.render() 就怎么传。例如 articles → { articles },posts → { posts }。
-
字段健壮性检查:示例中模板尝试渲染 article.description,但初始化数据仅含 subtitle。应提前校验或提供默认值,避免运行时异常:
<div class="card-text mb-2"><%= article.subtitle || 'No subtitle' %></div>
- 避免重复定义 app.set():你的路由文件中包含 app.set('view engine', 'ejs'); ——此配置应在主应用入口(如 app.js 或 server.js)中全局设置一次,切勿在路由模块中重复调用,否则可能引发不可预期行为。
✅ 最佳实践总结
| 场景 | 推荐做法 |
|---|---|
| 变量命名 | 使用语义清晰、复数形式的键名(如 articles, users),与数据结构一致 |
| 模板安全访问 | 对嵌套属性使用可选链(EJS 不原生支持,可用 article?.title || '' 替代)或三元判断 |
| 调试技巧 | 在模板顶部临时打印整个上下文:<%- JSON.stringify(Object.keys(locals), null, 2) %>,快速验证传入了哪些变量 |
| 结构分离 | 将数据获取逻辑(如数据库查询)从路由中抽离至 service 层,提升可维护性 |
遵循以上方法,不仅能立即解决 ReferenceError,更能构建出更健壮、易调试的 Express + EJS 应用结构。










