如何确定在foreach循环中发生的错误?

时间:2019-06-07 10:54:51

标签: javascript

我正在跟踪一个使用模块构建预算计算的教程。对于模块 budgetController 中的功能 calcTotal ,该人员使用forEach方法,我想将其重写为for循环。 在此功能中,我试图计算用户在网站上输入的所有费用和收入的总额。该值将传递到budgetController模块中的data.object。我在下面的完整代码中插入了不同的注释,以使其尽可能地易于理解。

    calcTotal = function(type){
    var sum = 0;

    data.allItems[type].forEach(function(cur){
    sum += cur.value;});

    data.totals[type] = sum;
    }

    var data = {
    allItems: {
    exp: [],
    inc: []
    },
    totals : {
    exp: 0,
    inc: 0 
    },
    budget: 0,
    percentage: -1
    };

上面的代码可以正常工作,但是我尝试对for循环执行相同操作,并且由于某些原因无法正常工作。

有人可以将calcTotal函数中的forEach方法重写为for循环,以便我可以看到我做错了什么吗? 这是完整的代码:

var budgetController = (function(){

var Expense = function(id, description, value){
this.id = id;
this.description = description;
this.value = value;
};

var Income = function(id, description, value){
this.id = id;
this.description = description;
this.value = value;
};


calcTotal = function(type){
var sum = 0;

data.allItems[type].forEach(function(cur){
sum += cur.value;});

data.totals[type] = sum;
}

var data = {
allItems: {
exp: [],
inc: []
},
totals : {
exp: 0,
inc: 0 
},
budget: 0,
percentage: -1
};

return{

addItem: function(type, des, val){
var newItem
var ID = 0;
if(data.allItems[type].length > 0 ){
ID = data.allItems[type][data.allItems[type].length - 1].id +1;
}
else{ID = 0};
//create new item based on exp or inc type
if (type === "exp"){
newItem = new Expense(ID, des, val)
}
else if(type === "inc"){
newItem = new Income(ID, des, val);
}
//Push it into our data structure
data.allItems[type].push(newItem);
//returning the new element
return newItem;
},
calculateBudget: function(){
//calculate total income and expenses
calcTotal("exp");
calcTotal("inc");
// calculate the totalBudget
data.budget = data.totals.inc - data.totals.exp;
// calculate the pecentage;
data.percentage = Math.round((data.totals.exp / data.totals.inc) * 100);
},
testing: function(){
console.log(data);
},
getBudget: function(){

return{
budget: data.budget,
expenses: data.totals.exp,
income: data.totals.inc,
percentage: data.percentege

}
}

}

})()


var UIcontroller = (function(){

getDOM = {
inputValue: ".add__value",
inputDescription: ".add__description",
inputType: ".add__type",
addButton: ".add__btn",
expensesList: ".expenses__list",
incomeList: ".income__list"
};
return {
getInput: function(){

return{
value: parseFloat(document.querySelector(getDOM.inputValue).value),
description: document.querySelector(getDOM.inputDescription).value,
type: document.querySelector(getDOM.inputType).value,

};


},

getDomStrings: function(){
return getDOM;
},
displayListItem: function(type, obj){

var html, newHtml, element

if(type === "exp"){

element = getDOM.expensesList;

html = '<div class="item clearfix" id="expense-%id%><div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__percentage">21%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>';
}
else if(type === "inc"){

element = getDOM.incomeList;

html = '<div class="item clearfix" id="expense%id%"><div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__percentage">10%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>';
}
newHtml = html.replace("%id%", obj.id);
newHtml = newHtml.replace("%description%", obj.description);
newHtml = newHtml.replace("%value%", obj.value)

document.querySelector(element).insertAdjacentHTML("beforeend", newHtml);
},


clearFields :function(){
var fields, arrayField
fields = document.querySelectorAll(getDOM.inputValue +"," + getDOM.inputDescription);
arrayField = Array.prototype.slice.call(fields);

fields.forEach(function(current, index, array){
current.value = "";
});
arrayField[0].focus();
}



}
})()


var controller = (function(budgetCntrl, cntrlUI){
var updateBudget = function(){
var budget

// Calculate the Budget

var calcBudget = budgetCntrl.calculateBudget();
// Return the Budget
budget = budgetCntrl.getBudget();
console.log(budget);
//Display the Budget in UI
}


var addItem = function(){
var input, newItem, addItems, clearFields
// Get the file input data
input = cntrlUI.getInput();
// add new Item to the budget Controller
newItem;
if(input.description !=="" &&  !isNaN(input.value) && input.value > 0){    
newItem = budgetCntrl.addItem(input.type, input.description, input.value);
// display Items in the user interface
addItems = cntrlUI.displayListItem(input.type, newItem);
// clear Fields
clearFields = cntrlUI.clearFields();
updateBudget();

// calculate the budget
// display Budget in the user interface
}
}
var setupEventListener = function(){
var DOM = cntrlUI.getDomStrings();
document.querySelector(DOM.addButton).addEventListener("click", addItem);
}
return{
init: function(){
console.log("app has started");
setupEventListener();
}
}


})(budgetController, UIcontroller)

controller.init();

我希望我很清楚。

1 个答案:

答案 0 :(得分:1)

此代码:

calcTotal = function(type){
var sum = 0;

data.allItems[type].forEach(function(cur){
sum += cur.value;});

data.totals[type] = sum;
}

可以重写为:

function calcTotal(type){
   var sum = 0;
   for (let i = 0; i < data.allItems[type].length; i++) {
     sum += data.allItems[type][i].value;
   }
   data.totals[type] = sum;
}

完整来源:https://jsfiddle.net/gpj40raf/2/

但是,我可以给您一些代码审查建议吗?

  • calcTotal取决于封闭环境中定义的数据。这不是一个好主意。最好将data作为参数传递(在某些情况下,使用闭包是好的,但这不是其中之一)。完整代码中的错误之一是calcTotal取决于下面定义的值。这将因为JavaScript吊起而起作用,但这不是一个好习惯。

  • 请注意,forEach代码取决于每个值都在value属性中,但是其余代码假定值是数字(即calculateBudget)。

  • 总计的计算可以轻松抽象,而无需依赖特定的data“形状”。例如:data.totals['type']=calcTotal(data.allItems['type'])。这样可以轻松了解发生了什么。

  • 看一下数组函数map / reduce / filter。他们所做的是以一种更具声明性的方式抽象某些模式。例如,要对值求和,可以使用:values.reduce((total, value)=>total+value, 0)(在一行中您可以表示为与calcTotal相同)。

  • 看看ES6构造。如今,所有新的浏览器都支持此功能,并且您可以将const / let,字符串文字和class用作ExpenseIncome。 ...代码将更短且易于阅读。