检查 EJS 模板中是否存在变量的正确方法是什么(使用 ExpressJS) ?

在 EJS github 页面上,只有一个简单的例子: Https://github.com/visionmedia/ejs

例子

<% if (user) { %>
<h2><%= user.name %></h2>
<% } %>

这似乎是在检查名为 user 的变量是否存在,如果存在,则执行一些操作。是吧?

我的问题是,如果用户变量不存在,Node 为什么会抛出 ReferenceError?这使得上面的示例毫无用处。检查变量是否存在的合适方法是什么?我需要使用 try/catch 机制并获取 ReferenceError 吗?

ReferenceError: user is not defined
at IncomingMessage.anonymous (eval at <anonymous> (/usr/local/lib/node/.npm/ejs/0.3.1/package/lib/ejs.js:140:12))
at IncomingMessage.<anonymous> (/usr/local/lib/node/.npm/ejs/0.3.1/package/lib/ejs.js:142:15)
at Object.render (/usr/local/lib/node/.npm/ejs/0.3.1/package/lib/ejs.js:177:13)
at ServerResponse.render (/usr/local/lib/node/.npm/express/1.0.7/package/lib/express/view.js:334:22)
at Object.<anonymous> (/Users/me/Dropbox/Projects/myproject/server.js:188:9)
at param (/usr/local/lib/node/.npm/connect/0.5.10/package/lib/connect/middleware/router.js:146:21)
at pass (/usr/local/lib/node/.npm/connect/0.5.10/package/lib/connect/middleware/router.js:162:10)
at /usr/local/lib/node/.npm/connect/0.5.10/package/lib/connect/middleware/router.js:152:27
at Object.restrict (/Users/me/Dropbox/Projects/myproject/server.js:94:5)
at param (/usr/local/lib/node/.npm/connect/0.5.10/package/lib/connect/middleware/router.js:146:21)

我知道我可以通过在我的服务器代码中添加一个“ user”本地变量来消除这个错误,但是这里的重点是我想要在运行时使用每天的 if/else nullcheck 类型模式来检查这些变量是否存在。一个不存在的变量的例外在我看来很荒谬。

117887 次浏览

与处理 js、 typeof foo == 'undefined'中的任何内容的方法相同,或者由于“ local”是包含它们的对象的名称,因此可以处理 if (locals.foo)。这只是原始的 js: p

我在使用 node.js 和 monose/Express/ejs 建立两个集合之间的关系时遇到过同样的问题,在这个例子中,admins.user _ id 存在,但是与一个不存在的 users.id 相关。
所以,找不到原因:

if ( typeof users.user_id.name == 'undefined' ) ...

“无法读取 null 的属性‘ name’” 然后我注意到我需要像这样做检查:

if ( typeof users.user_id == 'undefined' ) ...

我需要检查“名称”的“容器”,所以它工作了!
在那之后,这种做法的效果是一样的:

if ( !users.user_id ) ...

希望能有帮助。

您可以创建一个检查“ obj = = void 0”的视图助手,这个视图助手是为 Express.js 创建的:

res.locals.get = function() {
var args = Array.prototype.slice.call(arguments, 0);
var path = args[0].split('.');
var root = this;
for (var i = 0; i < path.length; i++) {
if(root[path[i]] === void 0) {
return args[1]?args[1]:null;
} else {
root = root[path[i]];
}
};
return root;
}

然后在视图中使用

<%- get('deep.nested.non.existent.value') %>  //returns: null
<%- get('deep.nested.non.existent.value', "default value") %> //returns: default value

要检查 user 是否已定义,您需要:

<% if (this.user) { %>
here, user is defined
<% } %>

我所做的只是传递一个默认对象,我称之为‘ data’=”,并将其传递给所有 ejs 模板。 如果需要将实际数据传递给 ejs 模板,请将它们添加为“ data”对象的属性。

这样,‘ data’对象总是被定义,并且永远不会得到未定义的错误消息,即使‘ data’属性存在于 ejs 模板中,但不在节点快速路由中。

对于您的 if语句,您需要使用 typeof:

<% if (typeof user == 'object' && user) { %>


<% } %>

尝试用 locals预置变量

例子: if(locals.user){}

<% if (locals.user) { %>


// Your logic goes here


<% } %>

我遇到了同样的问题,幸运的是,我发现 JS 中也有一个短路函数(我知道 Ruby 和其他一些语言中也有一个)。

在我的服务器/控制器端(来自 Node.js/Express) :

return res.render('result', {survey_result : req.session.survey_result&&req.session.survey_result.survey });

看到我做了什么吗?在可能未定义的变量(例如 request.session.survey_result对象,它可能有也可能没有表单数据)后面的 & & 是 JS 中的短路符号。它所做的只是评估 & & 后面的部分,如果 & & 左边的部分没有未定义。当左边的部分是 undefined时,它也不会抛出错误。它只是忽略它。

现在,在我的模板中(记住,我将对象 req.session.survey_result_survey对象作为 survey_result传递给我的视图) ,然后将字段呈现为:

<table>
<tr>
<td> Name:</td>
<td> <%=survey_result&&survey_result.name%></td>
</tr>
<tr>
<td> Dojo Location:</td>
<td> <%=survey_result&&survey_result.dojo_loc%></td>
</tr>
<tr>
<td> Favourite Language:</td>
<td> <%=survey_result&&survey_result.fave_lang%></td>
</tr>

我在那里也用了短路,只是为了保险起见。

当我用之前建议的方法尝试时,只需要:

<% if (typeof survey_result !== undefined) { %>
... <!-- some js and/or html code here -->
<% } %>

有时,它仍然会尝试计算 IF 语句中的属性... ... 也许有人可以解释一下为什么?

另外,我想纠正的是,undefined需要没有单引号,正如我在前面的例子中看到的那样。因为这个条件永远不会求值为 true,因为您将字符串值 'undefined'与数据类型 undefined进行比较。

来到这个页面寻找答案,但是我想出了一个更简短的内联语法,它是:

 <h2><%= user.name ? property.escrow.emailAddress : '' %></h2>

你可以使用这个技巧:

user.name // stops code execution,if user is undefined
(scope.user||0).name // === undefined

用户的父对象在哪里

如果打算经常使用同一个对象,可以使用如下函数:

<% function userObj(obj){
//replace user with what you name your object
if(typeof user === 'object'){
let result = user;
if(obj){
obj = obj.split('.');
for(let i = 0; i < obj.length; i++){
if(obj[i] && obj[i].trim() !== '' && result[obj[i]]){
result = result[obj[i]];
}else{
result = false;
break;
}
}
}
return result;
}
return false;
} %>

用途:

<% if(userObj('name')){
<h2><%= userObj('name') %></h2>
} %>

我想到了另一个办法。

<% if(user){ %>
<% if(user.name){ %>
<h1><%= user.name %></h1>
<%}}%>

希望这个能帮上忙。

我在 Joe Andrieu 的博客上找到了我认为更好的解决方案:

<%= user.name ? user.name : '' %>

与其他答案相比,这种方法适用于更多的情况(例如,当您需要检查单个属性是否存在时)。

这也许能帮到别人。

<p><%= locals?.message %></p>

或者

<p><%= locals.message || '' %></p>

对我来说最安全也是唯一的解决办法

<% if (typeof user !== 'undefined' && typeof user.name !== 'undefined') { %>
<h2><%= user.name %></h2>
<% } %>

或者长话短说

<% (typeof user !== 'undefined' && typeof user.name !== 'undefined') ? user.name : '' %>

2022年最新情况

使用局部变量对象

如果变量存在,这将打印它

<%= locals?.yourvariable %>

你也可以

如果变量存在,这将运行一个条件

<% if(locals.yourvariable) { %>
<% } %>

我在某个地方读到过使用当地语言并不完美,所以我想到了这样的例子:

明文规定:

const toRender = {
user: false,
};
//...
if (userExists) {
toRender.user = true;
toRender.data = userData;
}
res.render("site", {info: toRender});

和 ejs 模板:

<% if (info.user) { %>
<h2><%= info.data.name %></h2>
<% } %>