JavaScript系列_彻底理解闭包,如何彻底理解闭包,javascript中的闭包如何理解
导航:
一、概念
二、简单示例
三、使用闭包的注意事项
四、闭包的示例
说明一下:如果你对闭包的概念和简单使用会的话,那就可以直接看,第二大点的 第三步" 调用闭包(对闭包的深入理解,这个是重点"
详情:
一、 概念:
官方解释:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。(函数就是一个表达式)
通俗的来说:JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。
什么是闭包:闭包是指在函数外部访问函数作用域中变量(局部变量)的函数;或者说闭包就是能够读取其他函数内部变量的函数;或者说闭包是指有权访问另一个函数作用域中的变量的函数;由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。
二、 简单示例:
a) 定义闭包
function f1(){
var n =250;
functionf2(){//f2定义在f1的内部,可以读取f1的局部变量,f2是闭包;
n++;
alert(n);
}
returnf2;//返回f2的目的是外部可以调用f2函数,不至于,
因为,f2函数定义在f1内部,而导致外部不能调用。这样就相当
于f2还是可以在外部调用的。
}
b) 调用闭包(简单调用)
i. 第一步:调用f1(),把f()的返回值赋给f,f就是闭包函数f2。
var f = f1()//f就是f2。
ii. 第二步:调用f函数,也就是调用闭包函数f2
f();//调用f,就是调用f2。
c) 调用闭包(对闭包的深入理解,这个是重点)
i. 第一种调用法:
var f = f1();
f();//弹出251
f();//弹出252;
f();//弹出253
解释:对于函数f2来说,变量n相当于是全局变量。由于闭包可以让该变量n一直保持在内存中,所以,每次调用f()时,都使用上次的值。
ii. 第二种调用法:
1. f1()();//弹出251;
2. f1()();//弹出251;
3. f1()();//弹出251;
解释:本以为第二种调法和第一种调法是同样的意思,但是,结果却令人惊讶。为什么?
进一步解释:我们需要静下来心来,一定要静下心来,仔细人工执行这段代码。f1()()的执行过程:
1) 执行第一个括号,f1()。调用f1函数,先执行代码var n = 250定义了一个变量n,再执行代码function f2(){alert(n);}定义一个函数f2,最后代码return f2 把函数f2返回。
2) 执行第二个括号f1()(),调用f2函数,执行n++,n的值从上一步的250变为251,并弹出n,即弹出了251。
3) 当执行第二行的f()()时,还是重复上面两步:f1(),先调用函数f1,代码var n = 250定义了一个变量n,注意此处又重新定义了一个变量n,代码function f2(){alert(n);}定义一个函数f2,注意此处又重新定义了一个函数f2。f()()调用函数f2时,执行n++,n的值从前面的250变为251,并弹出n,即弹出了251。执行第三行的f()()时,是同样的道理,所以,注意:第二段代码f1()(),每次都会把f1先调用一次,而第一段代码只调用了一次f1。
三、 使用闭包的注意事项
a) 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。
b) 闭包会在父函数外部改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
四、 闭包的示例:
a) 循环里包含匿名函数(没有自我运行)
function test1(){
var arr = [];
for(var i=0; i<5; i++){
arr[i] = function(){
returni;
};//这个把函数对象赋给了数组的每个元素;
}
return arr;
}
let arr =test1();//arr是五个函数
arr[0]();//调用第一个函数
b) 循环里包含匿名函数(自我运行)
function test2(){
var arr = [];
for(var i=0; i<5; i++){
arr[i] = (function(){
return i;
})();//自运行函数,把匿名函数的执行结果赋给了数组的元素,这是函数的调用
}
return arr;//数组里分别保存了 0,1,2,3,4
}
c) 用闭包的方式实现mult(5)(6)(7),表示三个数的乘法(5*6*7)
解答:先求mult(5)(6);再求mult(5)(6)(7),完成需求时,一定要学会拆分。
第一步:完成mult(5)(6)
function mult(m){
return function (n){
return m*n;
}
}
console.log(mult(5)(6));
第二步:完成mult(5)(6)(7)
function mult(m){
return function (n){
return function(k){
return m*n*k;
};
}
}
console.log(mult(5)(6)(7));