闭包
闭包
闭包,获取一个局部作用域里变量的访问权限,涉及到作用域栈、执行上下文、垃圾回收机制、内存驻留以及性能问题,闭包切断作用域栈产生的垃圾回收事件,实现变量的内存驻留。主要应用场景在需要累积效应、重复循环事件、前后事件相关等。因而,为避免产生严重的性能问题,在完成事件任务后要把闭包置为null,释放内存。
这里介绍JS中作用域栈的特性,即先进后出,全局作用域位于栈底,局部作用域按照编译、执行顺序依次入栈,执行完毕依次出栈,对变量进行垃圾回收,释放内存。了解此特性,利用全局作用域始终位于栈底,并且总是最后完成垃圾回收,只要在局部作用域中装载具有全局效应的作用域,阻断垃圾回收,就完成了闭包的设计。
示例1
function foo(x) { var tmp = 3; return function (y) { console.log(x + y + tmp); x.memb = x.memb ? x.memb + 1 : 1; console.log(x.memb); } } var age = new Number(2); var bar = foo(age); // bar 现在是一个引用了age的闭包 bar(10);
示例2
function foo(x) { var temp = 3; return function (y) { console.log(x + y + (++temp)); } } var bar = foo(2); bar(10);
- 示例3
function badClosureExample() {
var as = document.querySelectorAll('a');
for (var i = 0; i < 4; i++) {
as[i].onclick = new popNum(i);
function popNum(oNum) {
return function () {
alert('单击第' + oNum + '个');
}
}
}
}
badClosureExample();
示例4
function badClosureExample() { var as = document.querySelectorAll('a'); for (var i = 0; i < 4; i++) { (function (i) { as[i].onclick = function () { alert('单击第' + i + '个'); } })(i); } } badClosureExample();
1、将变量 i 保存给在每个段落对象( p )上
function init() {
var pAry = document.getElementsByTagName("p");
for (var i = 0; i < pAry.length; i++) {
pAry[i].i = i;
pAry[i].onclick = function () {
alert(this.i);
}
}
}
init();
2、将变量 i 保存在匿名函数自身
function init() {
var pAry = document.getElementsByTagName("p");
for (var i = 0; i < pAry.length; i++) {
(pAry[i].onclick = function () {
alert(arguments.callee.i);
}).i = i;
}
}
init();
3、加一层闭包, i 以函数参数形式传递给内层函数
function init() {
var pAry = document.getElementsByTagName("p");
for (var i = 0; i < pAry.length; i++) {
(function (i) {
pAry[i].onclick = function () {
alert(i);
}
})(i);//调用时参数
}
}
init();
4、加一层闭包, i 以局部变量形式传递给内层函数
function init() {
var pAry = document.getElementsByTagName("p");
for (var i = 0; i < pAry.length; i++) {
(function () {
var index = i;//调用时局部变量
pAry[i].onclick = function () {
alert(index);
}
})();
}
}
init();
5、加一层闭包,返回一个函数作为响应事件(注意与3的细微区别)
function init() {
var pAry = document.getElementsByTagName("p");
for (var i = 0; i < pAry.length; i++) {
pAry[i].onclick = function (i) {
return function () { //返回一个函数
alert(i);
}
}(i)
}
}
init();
6、用 Function 实现,实际上每产生一个函数实例就会产生一个闭包
function init() {
var pAry = document.getElementsByTagName("p");
for (var i = 0; i < pAry.length; i++) {
pAry[i].onclick = new Function("alert(" + i + ")");
//new一次就产生一个函数实例
}
}
init();
7、用 Function 实现,注意与6的区别
function init() {
var pAry = document.getElementsByTagName("p");
for (var i = 0; i < pAry.length; i++) {
pAry[i].onclick =Function("alert(" + i + ")");
}
}
init();
示例5
var name = "The Window"; var object = { name: "My Object", getNameFunc: function () { return function () { return this.name; }; } }; alert(object.getNameFunc()()); //The Window
示例6
function outerFun() { var a = 0;
function innerFun() { a++; alert(a); } return innerFun; //注意这里} var obj = outerFun(); obj(); //结果为1 obj(); //结果为2