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()的返回值赋给ff就是闭包函数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,注意此处又重新定义了一个函数f2f()()调用函数f2时,执行n++n的值从前面的250变为251,并弹出n,即弹出了251。执行第三行的f()()时,是同样的道理,所以,注意:第二段代码f1()()每次都会把f1先调用一次,而第一段代码只调用了一次f1

JavaScript系列_彻底理解闭包,如何彻底理解闭包,javascript中的闭包如何理解

 三、  使用闭包的注意事项

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));