闭包 closure :
Observational: closure is a function instance remembering its outer variables even as that function is passed around and invoked in other scopes.
<pre>
<a href="">Visit the Apress website</a>
<p>I like <span>apples</span> and oranges.</p>
<a class="myclass1 myclass2" href="">Visit the W3C website</a>
</pre>
var pre = document.getElementsByTagName("pre")[0].children;
add_the_handlers(pre);
// error
var add_the_handlers = function (nodes) {
var i;
console.log(nodes.length);
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (e) {
alert(i);
};
}
};
nodes 节点可以绑定到 [0-1-2下标],但是 alert 执行时实际是对闭包环境变量的链接引用,此时 i 已经变成了3,因此最后点击时的 i 总会显示为3.
// ok
var add_the_handlers = function (nodes) {
var helper = function (i) {
return function (e) {
alert(i);
};
};
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = helper(i);
};
}
helper 创建了一个闭包,通过形参记录了每一个 i,同时 onclick 保持对该函数的引用,保持该词法环境一直存在。
onclick 触发时,每个执行函数都有自己对应的词法环境,每个环境里都有自己的 i 值。
// 更简单写法
var add_the_handlers = function (nodes) {
console.log(nodes.length);
for (let i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (e) {
alert(i);
};
}
};
每次循环都会创建新的 i
模块,模块模式。利用函数作用域和闭包创建被绑定对象与私有成员的关联。
举例:
var serial_maker = function () {
var prefix = '';
var seq = 0;
return {
set_prefix: function (p) {
prefix = String(p);
},
set_seq: function (s) {
seq = s;
},
gensym: function () {
var result = prefix + seq;
seq += 1;
return result;
}
}
}
var serialm = serial_maker()
serialm.set_prefix("qqqq")
serialm.set_seq(10000)
serialm.gensym()
->qqqq1000