EJS forEach / for 循环未定义问题
EJS forEach / for loop undefined issue
我定义了以下路线
app.get("/product/:category", (req, res, next) => {
const category = req.params.category
let selectedProducts = []
products.forEach(product => {
if(product.category === category)
selectedProducts.push(product)
})
res.render("category_view", {products: selectedProducts, customizationItems: customizationItems, category: category, header: category, pageType: ""});
});
它正在将一组对象发送到定义为“类别视图”的 ejs 文件。以下是
<%- include ("partials/header.ejs") %>
<div class="category-enclosure">
<div class="container">
<div class="row">
<div class="col s12">
<div class="category-list">
<!-- <div class="category-bar hideme" >
<h1><%-category%></h1>
</div> -->
<div class="searchbar" >
<input type="text" placeholder="Search For Product... ">
<i class="material-icons">search</i>
</div>
<% products.forEach(item => { %>
<div class="floating-product-img disabled" id="<%- item.id %>">
<img src="<%- item.img %>">
</div>
<div class="floating-customization-menu disabled" id="<%- item.id %>">
<div class="customize-header">
<h1>Chocolate Chip</h1>
<h2>.33</h2>
</div>
<div class="customize-body">
<form action="#">
<ul class="collection">
<% for(let i = 0; i < customizationItems.length; i++) { %>
<% if (item.toppings[i].title === customizationItems[i]) { %>
<li class="collection-item">
<div>
<p>
<label>
<input type="checkbox" class="filled-in" checked="checked" />
<span><%-item.toppings[i].title %></span>
</label>
</p>
</div>
<div>
<a href=""><i class="material-icons">remove_circle_outline</i></a>
<p></p>
<a href=""><i class="material-icons">add_circle_outline</i></a>
</div>
<div>
<h2><%-item.toppings[i].amount %></h2>
</div>
</li>
<% } else { %>
<li class="collection-item">
<div>
<p>
<label>
<input type="checkbox" />
<span><%-customizationItems[i] %></span>
</label>
</p>
</div>
<div>
<a href=""><i class="material-icons">remove_circle_outline</i></a>
<p></p>
<a href=""><i class="material-icons">add_circle_outline</i></a>
</div>
<div>
<h2></h2>
</div>
</li>
<% }%>
<% } %>
</ul>
</form>
</div>
<div class="customize-footer">
<div>
<h2>Total</h2>
<h2>.00</h2>
</div>
<div class="customize-footer-btns">
<a class="waves-effect waves-light btn cancle-btn">Cancle</a>
<a class="waves-effect waves-light btn">Add to Cart</a>
</div>
</div>
</div>
<div class="card category-card">
<div class="card-image waves-effect waves-block waves-light product-img">
<img src="<%-item.img%>">
<i class="image-expand-button fas fa-expand-alt" id="<%- item.id %>"></i>
</div>
<div class="card-content category-card-content">
<div class="category-card-title">
<span class="card-title activator grey-text text-darken-4"><%- item.name %></span>
<p>$<%- item.price %></p>
</div>
<div class="card-btns">
<div>
<i class="fas fa-angle-up activator"></i>
</div>
<div>
<a href=""><button>Add to Cart</button></a>
</div>
</div>
</div>
<div class="card-reveal">
<span class="card-title grey-text text-darken-4"><%- item.name %><i class="material-icons right">close</i></span>
<p>Here is some more information about this product that is only revealed once clicked on.</p>
<a class="waves-effect waves-light btn-small">Add to Cart</a>
<a class="waves-effect waves-light btn-small customize-btn" id="<%- item.id %>">Customize</a>
</div>
</div>
<%}) %>
</div>
</div>
</div>
</div>
<%- include ("partials/footer.ejs") %>
这是对象数组:
const products = [
{
id: "1",
name: "chocolate chip",
category: "cookies",
description: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever",
img: "https://images.unsplash.com/photo-1486428128344-5413e434ad35?ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
price: 6.33,
toppings: [{name: "cherries", amount: 2} , {name: "nuts", amount: 1}, {name: "chocolate flakes", amount: 1}]
},
{
id: "2",
name: "peanut butter",
category: "cookies",
description: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever",
img: "https://images.unsplash.com/photo-1519869491916-8ca6f615d6bd?ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
price: 4.77,
toppings: [{title: "cherries", amount: 1} , {title: "nuts", amount: 1}, {title: "chocolate flakes", amount: 1}]
},
{
id: "3",
name: "chocolate chip",
category: "cookies",
description: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever",
img: "https://images.unsplash.com/photo-1486427944299-d1955d23e34d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
price: 6.33,
toppings: [{title: "cherries", amount: 1} , {title: "nuts", amount: 1}, {title: "chocolate flakes", amount: 1}]
},
];
这是第二个数组:
const customizationItems = ["cholate drizzle", "chocolate flakes", "strawberries", "cherries", "nuts"]
在这个 ejs 文件中,我使用 forEach 语句遍历一个名为 products 的对象。这会为数组中的每个对象呈现一个元素。在此循环内,我还有一个“for 循环”,用于将 属性“customizationItems”下的数组与另一个数组进行比较,该数组是包含 forEach 语句的项目的 属性,这样引用“item.toppings[i].name”。但是,此 属性 在页面呈现时未优化。
我已经验证了这个 属性 不等于 undefined 只要“I”不超过“toppings array”的长度。通常,如果我与字符串数组进行比较,则没有问题,并且由于未定义的值而触发 else 语句,因为这两个数组的长度不同。
我想知道当“item.toppings[i].name”的值等于未定义时,为什么没有触发 else 语句呈现替代元素。
这是浏览器错误:
TypeError: /home/devindavis/Documents/webdev/bakery-project/views/category_view.ejs:28
26| <ul class="collection">
27| <% for(let i = 0; i < customizationItems.length; i++) { %>
>> 28| <% if ( item.toppings[i].title === customizationItems[i]) { %>
29| <li class="collection-item">
30| <div>
31| <p>
Cannot read property 'name' of undefined
at products.forEach.item (/home/devindavis/Documents/webdev/bakery-project/views/category_view.ejs:31:30)
at Array.forEach (<anonymous>)
at eval (/home/devindavis/Documents/webdev/bakery-project/views/category_view.ejs:16:17)
at category_view (/home/devindavis/Documents/webdev/bakery-project/node_modules/ejs/lib/ejs.js:691:17)
at tryHandleCache (/home/devindavis/Documents/webdev/bakery-project/node_modules/ejs/lib/ejs.js:272:36)
at View.exports.renderFile [as engine] (/home/devindavis/Documents/webdev/bakery-project/node_modules/ejs/lib/ejs.js:489:10)
at View.render (/home/devindavis/Documents/webdev/bakery-project/node_modules/express/lib/view.js:135:8)
at tryRender (/home/devindavis/Documents/webdev/bakery-project/node_modules/express/lib/application.js:640:10)
at Function.render (/home/devindavis/Documents/webdev/bakery-project/node_modules/express/lib/application.js:592:3)
at ServerResponse.render (/home/devindavis/Documents/webdev/bakery-project/node_modules/express/lib/response.js:1012:7)
查看ejs.render返回的错误:
27| <% for(let i = 0; i < customizationItems.length; i++) { %>
>> 28| <% if ( item.toppings[i].title === customizationItems[i]) { %>
正如您在问题中指出的那样,您正在使用 i
遍历 customizationItems
数组。但是随后您使用相同的索引来查看名为 toppings
的不同数组的元素。因此,尝试取消引用 item.toppings[i].title
可能会引发异常 - 超出 Javascript 中数组的范围不会引发异常,但取消引用未定义的值会。
进一步分解:
假设 item.toppings
是一个有 2 个元素的数组,而 customizationItems 有 4 个。
当 i = 2
、item.toppings[i]
试图从包含两项的数组中获取第三项时。这叫做越界,returns在javascript.
中未定义
所以在这个例子中,表达式 item.toppings[i].title
when item.toppings[i]
is undefined 正如我们刚才讨论的那样,试图从未定义的抛出中获取 title
属性 的值一个例外。
相反,您应该将数组迭代与循环内引用的元素相匹配。例如,查找与自定义项相同的置顶标题,我们可以像这样循环遍历两个数组:
for(let i = 0; i < customizationItems.length; i++) {
for(let n = 0; n < item.toppings.length; n++) {
if ( item.toppings[n].title === customizationItems[i]) {
// do stuff
这也可以这样写,完全消除了数字索引变量:
for(let customizationItem of customizationItems) {
for(let topping of item.toppings) {
if ( topping.title === customizationItem ) {
// do stuff
这样可以更容易地了解我们如何遍历两个数组并比较它们的内容。
我定义了以下路线
app.get("/product/:category", (req, res, next) => {
const category = req.params.category
let selectedProducts = []
products.forEach(product => {
if(product.category === category)
selectedProducts.push(product)
})
res.render("category_view", {products: selectedProducts, customizationItems: customizationItems, category: category, header: category, pageType: ""});
});
它正在将一组对象发送到定义为“类别视图”的 ejs 文件。以下是
<%- include ("partials/header.ejs") %>
<div class="category-enclosure">
<div class="container">
<div class="row">
<div class="col s12">
<div class="category-list">
<!-- <div class="category-bar hideme" >
<h1><%-category%></h1>
</div> -->
<div class="searchbar" >
<input type="text" placeholder="Search For Product... ">
<i class="material-icons">search</i>
</div>
<% products.forEach(item => { %>
<div class="floating-product-img disabled" id="<%- item.id %>">
<img src="<%- item.img %>">
</div>
<div class="floating-customization-menu disabled" id="<%- item.id %>">
<div class="customize-header">
<h1>Chocolate Chip</h1>
<h2>.33</h2>
</div>
<div class="customize-body">
<form action="#">
<ul class="collection">
<% for(let i = 0; i < customizationItems.length; i++) { %>
<% if (item.toppings[i].title === customizationItems[i]) { %>
<li class="collection-item">
<div>
<p>
<label>
<input type="checkbox" class="filled-in" checked="checked" />
<span><%-item.toppings[i].title %></span>
</label>
</p>
</div>
<div>
<a href=""><i class="material-icons">remove_circle_outline</i></a>
<p></p>
<a href=""><i class="material-icons">add_circle_outline</i></a>
</div>
<div>
<h2><%-item.toppings[i].amount %></h2>
</div>
</li>
<% } else { %>
<li class="collection-item">
<div>
<p>
<label>
<input type="checkbox" />
<span><%-customizationItems[i] %></span>
</label>
</p>
</div>
<div>
<a href=""><i class="material-icons">remove_circle_outline</i></a>
<p></p>
<a href=""><i class="material-icons">add_circle_outline</i></a>
</div>
<div>
<h2></h2>
</div>
</li>
<% }%>
<% } %>
</ul>
</form>
</div>
<div class="customize-footer">
<div>
<h2>Total</h2>
<h2>.00</h2>
</div>
<div class="customize-footer-btns">
<a class="waves-effect waves-light btn cancle-btn">Cancle</a>
<a class="waves-effect waves-light btn">Add to Cart</a>
</div>
</div>
</div>
<div class="card category-card">
<div class="card-image waves-effect waves-block waves-light product-img">
<img src="<%-item.img%>">
<i class="image-expand-button fas fa-expand-alt" id="<%- item.id %>"></i>
</div>
<div class="card-content category-card-content">
<div class="category-card-title">
<span class="card-title activator grey-text text-darken-4"><%- item.name %></span>
<p>$<%- item.price %></p>
</div>
<div class="card-btns">
<div>
<i class="fas fa-angle-up activator"></i>
</div>
<div>
<a href=""><button>Add to Cart</button></a>
</div>
</div>
</div>
<div class="card-reveal">
<span class="card-title grey-text text-darken-4"><%- item.name %><i class="material-icons right">close</i></span>
<p>Here is some more information about this product that is only revealed once clicked on.</p>
<a class="waves-effect waves-light btn-small">Add to Cart</a>
<a class="waves-effect waves-light btn-small customize-btn" id="<%- item.id %>">Customize</a>
</div>
</div>
<%}) %>
</div>
</div>
</div>
</div>
<%- include ("partials/footer.ejs") %>
这是对象数组:
const products = [
{
id: "1",
name: "chocolate chip",
category: "cookies",
description: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever",
img: "https://images.unsplash.com/photo-1486428128344-5413e434ad35?ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
price: 6.33,
toppings: [{name: "cherries", amount: 2} , {name: "nuts", amount: 1}, {name: "chocolate flakes", amount: 1}]
},
{
id: "2",
name: "peanut butter",
category: "cookies",
description: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever",
img: "https://images.unsplash.com/photo-1519869491916-8ca6f615d6bd?ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
price: 4.77,
toppings: [{title: "cherries", amount: 1} , {title: "nuts", amount: 1}, {title: "chocolate flakes", amount: 1}]
},
{
id: "3",
name: "chocolate chip",
category: "cookies",
description: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever",
img: "https://images.unsplash.com/photo-1486427944299-d1955d23e34d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
price: 6.33,
toppings: [{title: "cherries", amount: 1} , {title: "nuts", amount: 1}, {title: "chocolate flakes", amount: 1}]
},
];
这是第二个数组:
const customizationItems = ["cholate drizzle", "chocolate flakes", "strawberries", "cherries", "nuts"]
在这个 ejs 文件中,我使用 forEach 语句遍历一个名为 products 的对象。这会为数组中的每个对象呈现一个元素。在此循环内,我还有一个“for 循环”,用于将 属性“customizationItems”下的数组与另一个数组进行比较,该数组是包含 forEach 语句的项目的 属性,这样引用“item.toppings[i].name”。但是,此 属性 在页面呈现时未优化。
我已经验证了这个 属性 不等于 undefined 只要“I”不超过“toppings array”的长度。通常,如果我与字符串数组进行比较,则没有问题,并且由于未定义的值而触发 else 语句,因为这两个数组的长度不同。
我想知道当“item.toppings[i].name”的值等于未定义时,为什么没有触发 else 语句呈现替代元素。
这是浏览器错误:
TypeError: /home/devindavis/Documents/webdev/bakery-project/views/category_view.ejs:28
26| <ul class="collection">
27| <% for(let i = 0; i < customizationItems.length; i++) { %>
>> 28| <% if ( item.toppings[i].title === customizationItems[i]) { %>
29| <li class="collection-item">
30| <div>
31| <p>
Cannot read property 'name' of undefined
at products.forEach.item (/home/devindavis/Documents/webdev/bakery-project/views/category_view.ejs:31:30)
at Array.forEach (<anonymous>)
at eval (/home/devindavis/Documents/webdev/bakery-project/views/category_view.ejs:16:17)
at category_view (/home/devindavis/Documents/webdev/bakery-project/node_modules/ejs/lib/ejs.js:691:17)
at tryHandleCache (/home/devindavis/Documents/webdev/bakery-project/node_modules/ejs/lib/ejs.js:272:36)
at View.exports.renderFile [as engine] (/home/devindavis/Documents/webdev/bakery-project/node_modules/ejs/lib/ejs.js:489:10)
at View.render (/home/devindavis/Documents/webdev/bakery-project/node_modules/express/lib/view.js:135:8)
at tryRender (/home/devindavis/Documents/webdev/bakery-project/node_modules/express/lib/application.js:640:10)
at Function.render (/home/devindavis/Documents/webdev/bakery-project/node_modules/express/lib/application.js:592:3)
at ServerResponse.render (/home/devindavis/Documents/webdev/bakery-project/node_modules/express/lib/response.js:1012:7)
查看ejs.render返回的错误:
27| <% for(let i = 0; i < customizationItems.length; i++) { %>
>> 28| <% if ( item.toppings[i].title === customizationItems[i]) { %>
正如您在问题中指出的那样,您正在使用 i
遍历 customizationItems
数组。但是随后您使用相同的索引来查看名为 toppings
的不同数组的元素。因此,尝试取消引用 item.toppings[i].title
可能会引发异常 - 超出 Javascript 中数组的范围不会引发异常,但取消引用未定义的值会。
进一步分解:
假设 item.toppings
是一个有 2 个元素的数组,而 customizationItems 有 4 个。
当 i = 2
、item.toppings[i]
试图从包含两项的数组中获取第三项时。这叫做越界,returns在javascript.
所以在这个例子中,表达式 item.toppings[i].title
when item.toppings[i]
is undefined 正如我们刚才讨论的那样,试图从未定义的抛出中获取 title
属性 的值一个例外。
相反,您应该将数组迭代与循环内引用的元素相匹配。例如,查找与自定义项相同的置顶标题,我们可以像这样循环遍历两个数组:
for(let i = 0; i < customizationItems.length; i++) {
for(let n = 0; n < item.toppings.length; n++) {
if ( item.toppings[n].title === customizationItems[i]) {
// do stuff
这也可以这样写,完全消除了数字索引变量:
for(let customizationItem of customizationItems) {
for(let topping of item.toppings) {
if ( topping.title === customizationItem ) {
// do stuff
这样可以更容易地了解我们如何遍历两个数组并比较它们的内容。