NodeJS Express app.locals 不能在函数中直接访问

NodeJS Express app.locals are not directly accessible in function

这是一个奇怪的问题,但请跟我来。我有一个带有快速应用程序的 nodejs 服务器。在应用程序内部,我将我的本地人设置如下:

var moment = require('moment');
app.locals.moment = moment;

ejs 被渲染为:

exports.page = function (req, res) {
    res.render('first-page');
};

然后,在我的ejs中,我有以下代码:

<%
if (!moment) {
    throw new Error('moment is not defined');
}
function formatDate(date) {
     return moment(date).format();
}
%>
<p><%= formatDate(1435856054045); %></p>

有趣的是那一刻并没有引发异常。因此,正如文档所说,它是在 ejs 的范围内定义的。但是,ejs 引发了一个异常,表示该时刻未在 formatDate 中定义。如果我将 formatDate 更改为以下内容,一切正常。

function formatDate(date) {
     return locals.moment(date).format();
}

我的问题是在 ejs 中定义的函数是如何限定范围的以及它们应用了哪个上下文。 ejs 是否对函数应用了与浮动 javascript 不同的上下文?我假设它会做类似 formatDateFunctionPointer.call(ejsScope, ...);

的事情

当您 ejs 输出生成的函数(模板编译到的函数)时,问题变得很清楚:

with (locals || {}) {
  if (!moment) {
      throw new Error('moment is not defined');
  }
  function formatDate(date) {
    return moment(date).format();
  }
  ...
}

问题是你的formatDate函数被提升到了with块之外; 那个块里面,moment 实际上是 locals.moment,所以你测试它是否存在有效。

但是,当您可以 formatDate 时,它不在 with 块的上下文中 运行,因此 moment 不存在(但是 locals.moment 确实如此,正如您已经发现的那样)。

这是问题的一个独立示例:

var obj = { test : 123 };
with (obj) {
  if (test !== 123) throw new Error('test does not equal 123');
  function showTest() {
    console.log('test', test);
  }
  showTest();
}

解决这个问题的一种方法是使用函数表达式:

<%
if (typeof moment === 'undefined') {
  throw new Error('moment is not defined');
}
var formatDate = function(date) {
  return moment(date).format();
};
%>
<p><%= formatDate(1435856054045); %></p>

(它还修复了您的测试以查看 moment 是否实际定义)

或者您可以将 EJS _with 选项设置为 false