我知道如何实现闭包但我无法理解闭包发生的原因。例如:
function foo(){
var a = 4;
return function innerFoo(){
alert(a);
};
};
var bar = foo();
bar(); // alerts 4
我知道当我看到上面的代码时会发生什么,但是当我尝试逻辑地遵循它时,它没有意义。我认为我对执行上下文及其范围链的理解是错误的。
这就是我期望程序运行的方式:
function foo(){
var a = 4;
return function innerFoo(){
alert(a);
};
};
var bar = foo(); // function foo() is executed, creating a foo execution context(EC)
// fooEC = {scopeChain: [fooEV.VO, globalEC.VO],
// VO: {innerFoo: pointer to innerFoo(),
// a: 4}};
// So, the pointer to innerFoo() is returned to bar
// fooEC is exited
bar(); // bar points to code in innerFoo(), creates a innerFoo execution context
// innerFooEC = {scopeChain: [innerFoo.VO, globalEC.VO],
// VO: { }};
// interpreter searches innerFooEC.VO for variable "a", none found, looks
// down the scope chain at the global variable object,
// globalEC = {scopeChain: [globalEC.VO],
// VO: {foo: pointer to foo(),
// bar: pointer to innerFoo()}};
// a is undefined
我哪里出错了?
答案 0 :(得分:3)
错误在
bar points to code in innerFoo()
闭包不仅仅是指向代码的指针,它是指向代码加上环境的指针;这是定义a
的环境。
当你执行一个闭包时,范围链是一个活动的当关闭被定义时(即在foo
内),而不是那个进行调用的链。
请注意,闭包会捕获变量,而非值。这可以通过以下方式观察到:
function getset(x) {
var a = x;
function getter() { return a; }
function setter(x) { a = x; }
return [getter, setter];
}
var gs1 = getset(12);
var gs2 = getset(34);
console.log(gs1[0]()); // --> 12
console.log(gs2[0]()); // --> 34
gs1[1](1122);
gs2[1](3344);
console.log(gs1[0]()); // --> 1122
console.log(gs2[0]()); // --> 3344
即。每对getter / setter都会在两个闭包之间共享自己的变量,但是与另一对闭包。
根据我的经验,这是在循环中创建闭包的最常见错误的来源:
for (var i=0; i<10; i++) {
var node = document.createElement("div");
node.textContent = "click me (" + i + ")";
node.onclick = function() { alert(i); };
document.body.appendChild(node);
}
在此代码中,所有10个元素在单击时都会显示相同的数字(10),因为所有的闭包都共享了循环中使用的相同i
变量10是变量的最终值。