数学中的闭包与JS闭包
首先需要认识到一点,数学闭包和JS闭包是没有关系的。
数学上,闭包是指一个集合在某个运算下闭合,也就是对该集合进行某种运算,得到的结果仍属于该集合。
在JS中,百度百科援引官方的解释是:“闭包”指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。听起来有些难懂,那就让我们继续向下看吧。
闭包和什么有关系?
-
作用域:
在JS中,变量的作用域有两种,局部变量和全局变量。在函数内部可以访问函数外定义的变量,但在函数外部却不能访问函数内部的变量,这是JS的作用域在作怪。
let n = 'Hello!' ;
function a(){
var m = 'Bob.' ;//此处的var不能省略,如果省略,m就会变成全局变量。
console.log(n) ;
}
a();//Hello!
console.log(m);//error
上面的例子中,n是全局变量,作用于全局;
m是局部变量,作用于函数a的内部;
在函数内部可以正常输出n的值,但在函数外部却无法正常访问函数内部定义的变量。
-
作用域链:
看个例子,摘自CSDN的博客(Skycrab)
name="lwy";
function t(){
varname="tlwy";
functions(){
varname="slwy";
console.log(name);
}
functionss(){
console.log(name);
}
s();
ss();
}
t();
执行t()时,作用域链是:t()->window
执行s()时,作用域链是: s()->t()->window,所以name是”slwy";
执行ss()时,作用域链是: ss()->t()->window,所以name是”tlwy";
function createFunctions(){
var result =newArray();
for(var i=0; i < 10; i++){
result[i] =function(){
return i;
};
}
return result;
}
var funcs = createFunctions();
for(var i=0; i < funcs.length; i++){
console.log(funcs[i]());
}
输出10个10;WHY?
函数带()才是执行函数!
单纯的一句 var f = function() { alert('Hi'); }; 是不会弹窗的,后面接一句 f(); 才会执行函数内部的代码。类比上面的例子,也就是说,内部的函数在定义的时候就是在添加作用域链,循环的时候导致上级的i=10,然后在执行的时候,直接从顶级找到i,输出的自然就是10。
那怎么解决呢?
···
for(var i=0; i < 10; i++){
function num(i){
return function(){
return i;
}
result[i] = num(i);
};
···
- with语句。with语句主要用来临时扩展作用域链,将语句中的对象添加到作用域的头部。
person={name:"yhb",age:22,height:175,wife:{name:"lwy",age:21}};
with(person.wife){
console.log(name);
}
with语句将person.wife添加到当前作用域链的头部,所以输出的就是:“lwy".
with语句结束后,作用域链恢复正常。
闭包如何解决外部访问内部的变量的问题?
function a(){
var m = 'Bob.' ;
function b(){
console.log(m);
}
return b;
}
var A = a();
A();//Bob.
该例子中的b()就是闭包。
从上面的例子中可以看出,我们将内部变量通过嵌套一个内部函数b,在b中进行操作最后将b返回出去。这样在外部就可以访问到内部的变量了。
闭包的作用一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中(因为a()内部的函数b()的执行要依赖a()中定义的变量)。
在“脚本之家”里面有一个特别好的例子,如下所示:
function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result();// 999
nAdd();
result();// 1000
result实际上是函数f2;
nAdd是匿名函数且是全局变量,它本身也是一个闭包,在函数外部对函数内部的局部变量进行操作。
一些例子:
- (1)
var name = "name";
var people = {
name : "peopleName",
getName : function(){
return function(){
return this.name;
};
}
};
alert(people.getName()());//The Window
- (2)
function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
}
return innerFun;//注意这里
}
var obj=outerFun();
obj();//结果为1
obj();//结果为2
var obj2=outerFun();
obj2();//结果为1
obj2();//结果为2
- (3)
function outerFun()
{
var a =0;
alert(a);
}
var a=4;
outerFun();
alert(a);
结果是0,4. 因为在函数内部使用了var关键字 维护a的作用域在outFun()内部.
- (4)
function outerFun()
{
//没有var
a =0;
alert(a);
}
var a=4;
outerFun();
alert(a);
结果为0,0
闭包的缺点:
不必要的闭包会徒增内存消耗!