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.