JavaScript 具有函数级作用域,因此循环中的变量声明n(但不是document.getElementById('pieces').childNodes.item(i)to的赋值n)for实际上被提升到ready函数的顶部。
要理解这一点,假设您的代码实际上是这样编写的,因为 JavaScript 引擎实际上是这样解释它的:
function ready() {
var i, n;
for (i = 0; i < document.getElementById('pieces').childNodes.length; i++) {
n = document.getElementById("pieces").childNodes.item(i);
n.onmouseenter = function () { showBorder(n); };
n.onmouseleave = hideBorder;
}
}
The assignment of function () { showBorder(n); } to n's onmouseenter property creates a closure such that when that anonymous function actually executes it will have access to any and all data that was in scope at the time of creation, i.e. when the ready function is invoked. Thus, every one of those onmouseenter methods will have a reference to the variable n which, by the time ready's execution is complete, has a value equivalent to document.getElementById('pieces').childNodes.length.
I would suggest the following code snippet:
function ready() {
var pieces, i, l, n;
pieces = document.getElementById('pieces').childNodes;
for (i = 0, l = pieces.length; i < l; i++) {
n = pieces.item(i);
n.addEventListener('mouseover', (function (m) {
showBorder(m);
})(n), false);
n.addEventListener('mouseout', hideBorder, false);
}
}
- Declare all variables at the top of the scope so there's no confusion about their scope within the function context.
- Lookup
document.getElementById('pieces').childNodes once and assign that memory location to the pieces variable to avoid another lookup every time you need to reference that set of nodes.
- The comparison statement in the
for loop is executed every iteration so instead of looking up pieces.length repeatedly assign it to the variable l once and reference that variable each time instead.
- The use of
on<event> methods of a DOM element is, for the most part, the worst way to assign event handlers if for nothing else because you can only have a single function registered to a given DOM element at any time. The addEventListener method is the preferable way to assign handlers unless you expect your users to have an older version of Internet Explorer which instead uses the attachEvent method.
- The
mouseenter and mouseleave events were not standard DOM events but rather custom events added by Microsoft for older versions of Internet Explorer. They were added to the DOM Level 3 specification and Firefox and Opera introduced support for these events, but Webkit still does not support them.