Mat*_*rym 11 javascript methods closures function
我正在阅读"Javascript:The Good Parts",我对这里发生的事情感到非常困惑.将非常感谢更详细和/或简化的解释.
// BAD EXAMPLE
// Make a function that assigns event handler functions to an array of nodes the wrong way.
// When you click on a node, an alert box is supposed to display the ordinal of the node.
// But it always displays the number of nodes instead.
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (e) {
alert(i);
}
}
};
// END BAD EXAMPLE
Run Code Online (Sandbox Code Playgroud)
该add_the_handlers函数旨在为每个处理程序提供唯一的编号(i).它失败是因为处理函数绑定到变量i,而不是函数生成时变量的值i:
// BETTER EXAMPLE
// Make a function that assigns event handler functions to an array of nodes the right way.
// When you click on a node, an alert box will display the ordinal of the node.
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function (e) {
alert(i);
};
}(i);
}
};
Run Code Online (Sandbox Code Playgroud)
现在,我们不是为onclick分配函数,而是定义一个函数并立即调用它,传入i.该函数将返回一个事件处理函数,该函数绑定到i传入的值,而不是已i定义的值add_the_handlers.返回的函数被分配给onclick.
Dan*_*llo 20
我认为这是JavaScript新手的一个非常常见的混淆源.首先,我建议查看以下Mozilla Dev文章,简要介绍闭包和词法范围的主题:
让我们从坏的开始:
var add_the_handlers = function (nodes) {
// Variable i is declared in the local scope of the add_the_handlers()
// function.
var i;
// Nothing special here. A normal for loop.
for (i = 0; i < nodes.length; i += 1) {
// Now we are going to assign an anonymous function to the onclick property.
nodes[i].onclick = function (e) {
// The problem here is that this anonymous function has become a closure. It
// will be sharing the same local variable environment as the add_the_handlers()
// function. Therefore when the callback is called, the i variable will contain
// the last value it had when add_the_handlers() last returned.
alert(i);
}
}
// The for loop ends, and i === nodes.length. The add_the_handlers() maintains
// the value of i even after it returns. This is why when the callback
// function is invoked, it will always alert the value of nodes.length.
};
Run Code Online (Sandbox Code Playgroud)
正如Crockford在"好例子"中所建议的那样,我们可以用更多的闭包来解决这个问题.闭包是一种特殊的对象,它结合了两个东西:一个函数,以及创建该函数的环境.在JavaScript中,闭包的环境包含在创建闭包时在范围内的任何局部变量:
// Now we are creating an anonymous closure that creates its own local
// environment. I renamed the parameter variable x to make it more clear.
nodes[i].onclick = function (x) {
// Variable x will be initialized when this function is called.
// Return the event callback function.
return function (e) {
// We use the local variable from the closure environment, and not the
// one held in the scope of the outer function add_the_handlers().
alert(x);
};
}(i); // We invoke the function immediately to initialize its internal
// environment that will be captured in the closure, and to receive
// the callback function which we need to assign to the onclick.
Run Code Online (Sandbox Code Playgroud)
封闭函数不是让回调都共享一个环境,而是为每个回调函数创建一个新的环境.我们也可以使用函数工厂来创建一个闭包,如下例所示:
function makeOnClickCallback (x) {
return function (e) {
alert(x);
};
}
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = makeOnClickCallback(i);
}
Run Code Online (Sandbox Code Playgroud)