何为闭包
- 根据词法作用域的规则,内部函数总是可以访问其外部函数中声明的变量,当通过调用一个外部函数返回一个内部函数后,即使外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,我们就把这些变量的集合叫做闭包。
function fn1(){
var a =10;
function fn(){
console.log(a); // 10
}
return fn;
}
- 再比如下面的代码,随着函数的每次执行,变量的值都会进行递增1,原因是因为外层函数的变量处于内层函数的作用域链当中,被内层函数所使用着,当js垃圾回收机制读取到这一情况后就不会进行垃圾回收。
function fn1(){
var a = 1;
function fn(){
a++;
console.log(a);
}
return fn;
}
// 调用函数
var x = fn1();
x(); // 2
x();//3
- 闭包函数在js的开发当中是非常常见的写法,例如下面这种写法,功能是实现了对数组的一些常规操作的封装,也是属于对闭包函数的一种应用。
let Utils = (function(){
var list = [];
return {
add:function(item){
if(list.indexOf(item)>-1) return; // 如果数组内元素存在,那么不在重复添加
list.push(item);
},
remove:function(item){
if(list.indexOf(item) < 0) return; // 如果要删除的数组数组之内不存在,那么就返回
list.splice(list.indexOf(item),1);
},
get_length:function(){
return list.length;
},
get_showData:function() {
return list;
}
}
})();
Utils.add("hello,world");
Utils.add("this is test");
console.log(Utils.get_showData());// ["hello,world","this is test"]
在上面的代码中,函数嵌套函数形成了闭包函数的结构,在开发中是比较常见的写法。
闭包的概念:闭包是指有权限访问上一级父作用域的变量的函数.
闭包函数的应用
- 闭包函数是js当中非常重要的概念,在诸多的地方可以应用到闭包,通过闭包,我们可以写出很多优秀的代码,下面是一些常见的内容:
// 数组排序
[1, 2, 3].sort(function (a, b) {
... // 排序条件
});
// map方法的应用,根据函数中定义的条件将原数组映射到一个新的数组中
[1, 2, 3].map(function (element) {
return element * 2;
}); // [2, 4, 6]
// 常用的 forEach
[1, 2, 3].forEach(function (element) {
if (element % 2 != 0) {
alert(element);
}
}); // 1, 3
- 例如我们常用的call和apply方法,它们是两个应用函数,也就是应用到参数中的函数(在apply中是参数列表,在call中是独立的参数):
(function () {
alert([].join.call(arguments, ';')); // 1;2;3
}).apply(this, [1, 2, 3]);
- 还有最常使用的写法:
var a = 10;
setTimeout(function () {
alert(a); // 10, after one second
}, 1000);
- 当然,ajax的写法也就是回调函数其实本质也是闭包:
//...
var x = 10;
// only for example
xmlHttpRequestObject.onreadystatechange = function () {
// 当数据就绪的时候,才会调用;
// 这里,不论是在哪个上下文中创建
// 此时变量“x”的值已经存在了
alert(x); // 10
};
//...
- 当然也包括我们上边说的封装独立作用域的写法:
var foo = {};
// 初始化
(function (object) {
var x = 10;
object.getX = function _getX() {
return x;
};
})(foo);
alert(foo.getX()); // 获得闭包 "x" – 10