0
点赞
收藏
分享

微信扫一扫

一文详解js闭包,初学者也能学会的闭包

目录

一、前提知识:变量的作用域

二、闭包的理解

三、闭包的作用

四、常见的闭包使用形式

五、闭包的生命周期

六、注意事项 


一、前提知识:变量的作用域

变量的作用域分为全局作用域和局部作用域,也就是全局变量和局部变量。JavaScript有一个特殊的地方是函数内部可以直接读取全局变量,但是在函数外部,无法读取到函数内部的变量。

  • 函数内部直接读取全局变量:
//函数内部直接读取全局变量
var a = 100
function fn1(){
   console.log(a)
}
fn1() //100
  • 函数外部无法读取函数内的局部变量
//函数外部无法读取函数内的局部变量
function fn1(){
    var a = 100
}
console.log(a) //error

这里注意:在函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上声明了一个全局变量!

function fn1(){
    a = 100
}
console.log(a) //100

那么问题来了:

对函数内部变量进行一系列操作之后,需要在函数外部访问到,怎么才能实现呢?这就需要使用闭包了。

二、闭包的理解

针对上述问题:我们可以在函数内部嵌套一个子函数,将子函数作为外部函数的返回值。如下:

<script>
    function fn1(){
      var myName = "唯一的阿金"
      function fn2(){
        console.log("myName = ",myName)
      }
      return fn2
    } 
    var result = fn1()
    result() 
</script>

打印结果如下:

 

在上面的代码中,函数 fn2 被包括在函数 fn1 内部,这时 fn1 内部的所有局部变量,对 fn2 都是可见的。但是,fn2 内部的局部变量,对 fn1是不可见的。这是 Javascript 特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

我们可以利用这一特点,把 fn2 作为返回值,就可以在fn1函数外部访问 fn1 的内部变量了。这个fn2函数,就是闭包。

简单理解,闭包就是能读取函数内部变量的函数。

闭包的产生条件:

三、闭包的作用

 闭包有两大作用:

<script>
    function fn1(){
      var myName = "唯一的阿金"
      addName = function(){
        myName += ",你好!"
      }
      function fn2(){
        console.log("myName = ",myName)
      }
      return fn2
    } 
    var result = fn1()
    result()
    addName()
    console.log("*****调用addName()后****")
    result()
</script>

打印结果如下:可以看到函数内部的局部变量myName在函数调用后并没有被销毁,在执行addName函数(它是一个全局变量)后,改变了myName变量的值。

四、常见的闭包使用形式

1. 将函数作为另一个函数的返回值使用

这种形式,上述代码已经演示过,这里不再赘述。

2.将函数作为实参传递给另一个函数调用

function showDelay(msg,time){
    setTimeout(function(){
        console.log(msg)
      },time)
    }
showDelay("唯一的阿金,你好!",1000)

setTimeout()函数的第一个参数是函数,同时函数内部调用了外部函数showDelay()的局部变量,因此产生了闭包。

 

闭包的应用主要有:

五、闭包的生命周期

 1. 产生:在内部函数定义执行时产生

<script>
    function fn1(){
      var myName = "唯一的阿金"
      function fn2(){
        console.log("myName = ",myName)
      }
      return fn2
    } 
    var result = fn1()  //产生闭包
    result() 
</script>

 2. 死亡:在内部函数成为垃圾对象时 

<script>
    function fn1(){
      var myName = "唯一的阿金"
      function fn2(){
        console.log("myName = ",myName)
      }
      return fn2
    } 
    var result = fn1()  //产生闭包
    result = null //闭包死亡
</script>

六、注意事项 

1. 闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。

  • 解决方法:在退出函数之前,将不使用的局部变量全部删除。

2. 由于闭包会在父函数外部,改变父函数内部变量的值。因此,在把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value)时,要小心,不要随便改变父函数内部变量的值。

举报

相关推荐

0 条评论