对Javascript闭包的理解

1。首先,我们需要知道行动的可变链。

变量的范围分为两类:全局变量和局部变量,没有定义函数中的变量是全局变量。函数中定义的变量是局部变量。注意,当变量在函数中定义时,我们必须使用var关键字和变量,而不使用var关键字作为全局变量。

在Javascript中每个代码都有其相关的作用域链,它是一个对象列表或链表,它定义了变量在本规范的范围。从全局变量的顶层代码范围;范围链没有嵌套函数有两个目的:一是目标函数的参数和局部变量,全局变量和对象;嵌套函数的作用域链有三个参数:目标函数参数和局部变量在全局变量和局部变量的函数,函数可以访问对象的作用域链,所以函数可以访问全局变量,反之亦然,即他们不能在函数访问局部变量。


var a=1;
函数围(){
警报(a);
var m=10;
n=20;
}

外部变量(1);;内部函数可以访问全局变量。
警报(m);错误;局部变量错误的外部访问功能
警报(n);20;;不使用var关键字的内部函数变量的定义,它是一个全局变量,即外部访问。


2。如何读取外部变量

有时候,我们需要访问外部功能的内板的局部变量,这个时候就需要使用一个变量的方法来实现它。我们使用Javascript变量域的特点,在函数定义的函数,而函数可以访问父函数的变量。


函数围(){
var m=10;
函数内(){
警报(M);
}
返回内;
}

var(=);
Nei()函数是一个局部变量,而不是在外部访问中。
f(10);


三.关闭

最后一个代码的内部()函数是一个闭包。从上面,我们可以看到闭包是一个函数,它可以读取函数中的局部变量,并定义为函数内部的函数。从本质上说,它可以看作是连接功能内部和外部功能的桥梁。

闭包有两个函数。

第一个变量是可以在函数内部读取的变量。

二是将这些局部变量保存在内存中,实现变量数据共享。


函数围(){
var m=99;
函数内(){
警报(M);
米+;
}
返回内;
}

var(=);
f(99);
f(100);
f(101);


当函数在上面运行时,变量m被保存到内存中,而f()的执行可以读取m的值,但是直接警报(M)不能!

我们也可以把参数传递给闭包函数。如下面的示例所示,我们定义了一个匿名函数,并返回一个闭包函数,该函数将传入参数添加到匿名函数中的本地变量i中,并增加i。


var =(函数(){())
var I=0;
返回函数(数字){
数字= i;
警报(努姆);
++;
}
});
围(1);1
围(2);3
围(3);5


为了更深入地了解闭包,我们来看看下面的例子:

现在我想定义一个返回数组的函数,数组的每个元素都是一个函数,每个函数都会弹出相应的索引值。

我们可以写这个


函数框(){
var arr = { };
对于(i = 0;i < 5;i + +){
ARR {我} =函数(){ return我;}
}
报酬;
}
var =;
警报(a);数组包含主体的五个函数
警报({ 0 })(5);
警报({ 1 })(5);


上面的代码中发现5弹出不是0,1,2,3,4所期望的,但那是因为我也在内存中的局部变量。当我们运行{ 0 }()时,i的值是5,并且i的值在框()函数中不断增加。

解决方案:闭包的实现


函数框(){
var arr = { };
对于(var i = 0;i < 5;i + +){

ARR {我} =(function(NUM){)
返回函数(){返回数;}
})(一);

}
报酬;
}

var arr =箱();

对于(var i = 0;i < 5;i + +){

警报(ARR {我}()); / / 0,1,2,3,4
}


4。注意闭包的使用

1)因为闭包可以使函数中的变量存储在内存中,并且内存消耗很大,所以不能滥用。否则,它会导致网页的性能问题,并可能导致IE.内存泄漏。解决方案是删除在功能退出之前没有使用的所有本地变量。

2)关闭将在母函数的外部变化的母函数内部的变量的值。因此,如果你把母函数作为一个对象(object),使用封闭的常用方法(公共法)和以内部变量为私有财产(私人价值),我们必须小心,不要随意更改父功能的价值。



5。下面是关于闭包的几个问题。

如果您能够理解以下代码的运行结果,您应该了解闭包的操作机制。

JS代码




窗口;
var对象{ { {
名称:我的对象
GetNameFunc:函数(){
返回函数(){
返回this.name;这 / / = >嵌套函数作为全局变量或不确定的,不能承受这个功能
};
}
};
警报(object.getnamefunc()()); / /窗口


上面的输出窗口,因为这不继承父函数嵌套函数,它的值是全局变量或定义(ecmascript5以下),所以它返回全局对象的名称的变量。让它返回的对象的名称属性,代码如下:


窗口;
var对象{ { {
名称:我的对象
GetNameFunc:函数(){
var =;
返回函数(){
返回cur.name;
};
}
};
警报(对象。getnamefunc)(()); / / =我的对象


上面的代码将父函数对象的这一个分配给当前变量,它的嵌套函数可以通过当前变量访问它的属性。

------------------------------------------------------------------------------------------------------

javascript关闭的例子




outerfun()函数
{
var a=0;
innerfun()函数
{
++;
警报(a);
}
}
InnerFun(); / / = >错误


上面的代码是wrong.innerfun()范围内outerfun(),并在外部调用outerfun是错误的()。

改为以下,即关闭:

JS代码


outerfun()函数
{
var a=0;
innerfun()函数
{
++;
警报(a);
}
返回innerfun; / /注意这里
}
var obj = outerfun();
Obj(1); / /结果
Obj(2); / /结果
var obj2 = outerfun();
obj2(1); / /结果
obj2(2); / /结果


什么是壁橱:

当内部函数在定义内部闭包函数时定义在外部范围内时,如果外部函数变量中的内部函数引用,当外部函数调用完成时,这些变量不会在内存中释放,因为它们需要闭包。

--------------------------------------------------------------------------------------------------------

再看一个例子

JS代码




outerfun()函数
{
var a=0;
警报(a);
}
var a=4;
outerfun(0); / / = >
警报(a);4


结果4。因为var关键字使用里面的功能维持的一outfun范围内()。

再看下面的代码:

JS代码


outerfun()函数
{
无var
a = 0;
警报(a);
}
var a=4;
outerfun(0); / / = >
警报(a);0


结果是,0,0真是奇怪。为什么

范围链是描述路径的术语。变量的值可以沿着这条路径确定。在执行a = 0时,由于不使用var关键字,分配操作将沿着范围链运行到var a = 4,并更改其值。