闭包:逐行解释“Javascript:好的部分";例子? [英] Closures: Line by Line explanation of "Javascript: Good Parts" example?
问题描述
我正在阅读Javascript: The Good Parts",完全被这里发生的事情搞糊涂了.更详细和/或简化的解释将不胜感激.
I'm reading "Javascript: The Good Parts" and am totally baffled by what's really going on here. A more detailed and/or simplified explanation would be greatly appreciated.
// 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
add_the_handlers
函数旨在为每个处理程序提供一个唯一编号 (i).它失败是因为处理函数绑定到变量 i
,而不是函数创建时变量 i
的值:
The add_the_handlers
function was intended to give each handler a unique number (i). It fails because the handler functions are bound to the variable i
, not the value of the variable i
at the time the function was made:
// 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);
}
};
现在,我们不再为 onclick 分配一个函数,而是定义一个函数并立即调用它,传入 i
.该函数将返回一个事件处理函数,该函数绑定到传入的 i
的值,而不是绑定到 add_the_handlers
中定义的 i
.返回的函数被分配给 onclick.
Now, instead of assigning a function to onclick, we define a function and immediately invoke it, passing in i
. That function will return an event handler function that is bound to the value of i
that was passed in, not to the i
defined in add_the_handlers
. That returned function is assigned to onclick.
推荐答案
我认为对于 JavaScript 新手来说,这是一个非常常见的混淆来源.首先,我建议查看以下 Mozilla Dev 文章,以简要介绍闭包和词法范围的主题:
I think this is a very common source of confusion for newcomers to JavaScript. First I would suggest checking out the following Mozilla Dev article for brief introduction on the topic of closures and lexical scoping:
让我们从坏的开始:
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.
};
我们可以用更多的闭包来解决这个问题,正如克罗克福德在好例子"中所建议的那样.闭包是一种特殊的对象,它结合了两件事:函数和创建该函数的环境.在 JavaScript 中,闭包的环境由创建闭包时在范围内的所有局部变量组成:
We can tackle this problem with more closures, as Crockford suggested in the "good example". A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. In JavaScript, the environment of the closure consists of any local variables that were in-scope at the time that the closure was created:
// 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.
闭包函数不是让所有回调共享一个环境,而是为每个回调创建一个新环境.我们也可以使用函数工厂来创建闭包,如下例所示:
Rather than having the callbacks all sharing a single environment, the closure function creates a new environment for each one. We could also have used a function factory to create a closure, as in the following example:
function makeOnClickCallback (x) {
return function (e) {
alert(x);
};
}
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = makeOnClickCallback(i);
}
这篇关于闭包:逐行解释“Javascript:好的部分";例子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!