我得到了以下完美的代码。它的作用是:在表格中,当您将鼠标悬停在任何表格单元格上时,它会突出显示相应的表格标题单元格和表格第一列单元格。
// Row & Column Highlight
(function() {
var gridCellRow = null,
gridCellCol = null,
tableElement = document.getElementsByClassName('inner_table');
for (var i = 0, len_i = tableElement.length; i < len_i; i++) {
if (tableElement[i].getElementsByClassName('row_label_cell').length > 0) {
var gridCell = tableElement[i].getElementsByClassName('input_cell');
for (var j = 0, len_j = gridCell.length; j < len_j; j++) {
function gridCellParents(currentCell) {
return gridCellRow = currentCell.parentNode.firstElementChild,
gridCellCol = currentCell.parentNode.parentNode.rows[0].cells[currentCell.cellIndex];
}
gridCell[j].addEventListener('mouseover', (function() {
gridCellParents(this);
gridCellRow.classList.add('highlight');
gridCellCol.classList.add('highlight');
}));
gridCell[j].addEventListener('mouseout', (function() {
gridCellRow.classList.remove('highlight');
gridCellCol.classList.remove('highlight');
}));
}
}
}
}());
然而,JSHint告诉我,
for (var j = 0, len_j = gridCell.length; j < len_j; j++) {
function gridCellParents(currentCell) {
return gridCellRow = currentCell.parentNode.firstElementChild,
gridCellCol = currentCell.parentNode.parentNode.rows[0].cells[currentCell.cellIndex];
}
不是最佳实践&#34;函数声明不应放在块中。使用函数表达式或将语句移动到外部函数的顶部。&#34;
以及
gridCell[j].addEventListener('mouseover', (function() {
gridCellParents(this);
gridCellRow.classList.add('highlight');
gridCellCol.classList.add('highlight');
}));
gridCell[j].addEventListener('mouseout', (function() {
gridCellRow.classList.remove('highlight');
gridCellCol.classList.remove('highlight');
}));
}
不是最佳做法&#34;不要在循环中制作函数。&#34;
那么我如何正确地根据最佳实践建立这个整体功能呢?
答案 0 :(得分:2)
功能减速不应该在循环内,因为它没有 感觉一遍又一遍地重新创造同样的功能 “连续流动”(不同于其他相同功能的情况) 可能会在更复杂的代码中再次创建)。主要原因是 因为hoisting而且强烈反对javascript 在循环中编写函数声明的原则。
一个很好的起点,有一个更有序的代码:
// Row & Column Highlight
(function() {
var gridCellRow,
gridCellCol,
gridCell,
tableElement = document.getElementsByClassName('inner_table');
function gridCellParents(currentCell) {
gridCellRow = currentCell.parentNode.firstElementChild,
gridCellCol = currentCell.parentNode.parentNode.rows[0].cells[currentCell.cellIndex];
}
function onMouseEnter() {
gridCellParents(this);
gridCellRow.classList.add('highlight');
gridCellCol.classList.add('highlight');
}
function onMuoseLeave() {
gridCellRow.classList.remove('highlight');
gridCellCol.classList.remove('highlight');
}
for (var i = 0, len_i = tableElement.length; i < len_i; i++) {
if (tableElement[i].getElementsByClassName('row_label_cell').length > 0) {
gridCell = tableElement[i].getElementsByClassName('input_cell');
for (var j = 0, len_j = gridCell.length; j < len_j; j++) {
gridCell[j].addEventListener('mouseenter', onMouseEnter);
gridCell[j].addEventListener('mouseleave', onMuoseLeave);
}
}
}}());
正如您所看到的,我已将您的活动修改为mousenter和mouseleave,这可能更适合您的需求,并且可以提升整体效果。
// Row & Column Highlight
(function() {
var gridCell,
tableElement = document.querySelectorAll('.inner_table');
function getCellParents(cell){
return {
row : cell.parentNode.firstElementChild, // row
col : cell.parentNode.parentNode.rows[0].cells[cell.cellIndex] // col
};
}
function updateGridCellParents(cell, state) {
state = state ? 'add' : 'remove';
var parents = getCellParents(cell);
parents.row.classList[state]('highlight');
parents.col.classList[state]('highlight');
}
funciton checkTarget(target){
// make sure the element is what we expected it to be
return target.className.indexOf('input_cell') != 0;
}
function onMouseEvents(e){
checkTarget(e.target) && updateGridCellParents(e.target, e.type == "mouseover");
}
document.body.addEventListener('mouseover', onMouseEvents);
document.body.addEventListener('mouseout', onMouseEvents);
})();
答案 1 :(得分:2)
除了上一个答案之外,我认为重要的是还要说明为什么这是一种不好的做法。
在循环内创建函数时的问题是它们经常使用依赖于循环迭代的值。让我们举个例子。
// Create three function, that writes their number
var funcs = [];
for(var i=0; i<3; i++){
funcs.push(function(){
document.write(i);
});
}
// Call them.
funcs.forEach(function(f){
f();
});
&#13;
可以预期上面的代码写1然后是2然后3.但是,因为JS中的变量不是块作用域而是函数作用域(新的let
和const
除外),所有这三个函数的闭包实际上将使用完全相同的i
:3,它给出的最后一个值(因此它仍然具有的值)。
由于这种行为,这很容易出错。因此,不建议这样做。
如果您需要创建一个取决于循环值的函数,您可以使用工厂。
// Create a factory function that returns a
// function that writes the argument.
function writerFactory(msg){
return function(){
document.write(msg);
}
}
// Create three functions, that write their number.
var funcs = [];
for(var i=0; i<3; i++){
funcs.push(writerFactory(i));
}
// Call them.
funcs.forEach(function(f){
f();
});
&#13;
这次,每个函数都有一个不同的闭包:每次调用工厂创建的闭包。他们都可以访问不同的msg
。