js闭包通俗解析

开场白

对于js来说,闭包可谓时重点和难点,前端面试应该是必问的题,对闭包的理解程度就可以看的出一个前端开发的功底。网上对闭包的文章比比皆是,但是对于初学者来说不是很友好。今天我就考虑一下初学者,毕竟我还算是吧,简单通俗的讲一下js闭包。

准备工作

要修炼js的闭包功夫,还需要一点其他功力作为功底的。

  • 功底一:js的垃圾回收知识
  • 功底二:js的函数执行过程
  • 功底三:js的全局变量和局部变量

大概就明白这三点就可以理解闭包了吧。对这三点也就理解个基本 不用过深的理解比较复杂的情况,如js的预处理机制,js的堆栈内存,js的变量提升什么的。

现在我们就简单学习一个上面三套功法。都是之学招式不学精髓。

看了一下功底三最为好学。一句话 函数内生成的变量叫局部变量 函数外生成的变量叫全局变量 话不严谨应该好理解,其实后面还有两句,函数内可以访问全局变量,函数外访问不了局部变量 ;太长了不太好记。用例子来说吧。

   var a = 'AAAA';
   function fn() {
       var b = 'BBB';
       console.log(a)  //打印AAA
   }
   fn();
   console.log(b)  // b is not defined

上面例子就不解释了。。。

再看一下js的垃圾回收机制:也是一句话 局部变量在函数执行完成之后自动回收 就拿上面的函数来说,当fn执行完成之后函数内创建的变量会自动回收

最麻烦的功底二来了,关于函数的执行过程,基础的就是函数开始不执行,调用之后从上到下依次执行,编译错误和return就结束,但是复杂的就是有函数的 有return的。举个例子吧


   function fn() {
       var b = 'BBB';
       return function () {
          console.log("CCCC")
       }
   }
   fn();

咱们来分步执行一下 

  1. 代码开始了走到fn(){} 这个函数,没有执行语句跳过它。
  2. 走到fn() 开始执行fn这个函数  最终返会了一个函数。结束
  3. 函数结束 局部变量 b 被回收

再变一下型 往后加个剧本

   function fn() {
       var b = 'BBB';
       return function () {
          console.log("CCCC")
       }
   }
  var c = fn();
  c();

接上面的 返回一个函数  functio(){console.log('CCC')} 赋值给 c这个变量;(加一句:b被回收) 接着执行c() 这个函数打印出CCC(加一句 如上面return的函数内定义变量,也会被回收)

闭包开讲

准备工作完成之后一个普通函数的经历过程应该可以看的懂了吧。

那就看一个例子一步一步执行一下

/*1*/  function fn() {
/*2*/      var b = 'BBB';
/*3*/       return function () {     
/*4*/         console.log(b)
/*5*/       }
/*6*/   }
/*7*/  var c = fn();
/*8*/  c();
/*9*/  c();
/*10*/ c();

函数有点长给标一个行号 ;长函数不要着急 一步一步来。 

  1. 1-6行定义了一个函数不执行
  2. 第7行返回了一个函数 
    function () {
            console.log(b)
      } 赋值个变量c   c就是该函数了
  3. 按照上面的垃圾回收 函数内的b变量被回收
  4. 第8行执行函数c 打印b,因为b被销毁了 所以应该是  b is not defined 结束 9行10行就不执行了

代码复制运行 垃圾小编 不对!  看来js处理和我们想的不一样。

那就一起来分析一下吧? 结果显示 打印了三个 BBB,说明程序中没有出错,也就说b变量没有被销毁,再说一下就是外面可以访问内部函数定义的变量;这就生成了闭包。闭包最核心的也就是打破了js的垃圾回收机制,让局部变量不被销毁。曾看到一篇文章把闭包比喻成一个背包,可以把函数的变量放进去,当它被返回时就一起带走了。

那咱们再走一边上面程序,加一句话

   /*1*/  function fn() {
   /*2*/      var b = 'BBB';
   /*3*/       return function () {
   /*4*/         b = b+'B'
   /*5*/         console.log(b)
   /*6*/       }
   /*7*/   }
   /*8*/  var c = fn();
   /*9*/  c();
   /*10*/ c();
   /*11*/ c();
  1. 1-7行定义一个函数
  2. 第8行返回了一个函数 
    function () {
            b = b+'B'
            console.log(b)
      } 赋值个变量c   c就是该函数了
  3. 因为返回的函数 用到fn这个函数内生成的b变量。所以就打开背包把 b='BBB',给背走了,就成了以下函数
    var b = 'BBB'
    function () {
             b = b+'B'
             console.log(b)
           }
  4. 第九行执行c函数两步① b 的值改为为'BBB'+'B'  为BBBB ② 打印'BBBB'
  5. 第10行再执行c函数 刚才把b的值已经改为'BBBB'了 再加一个B 打印'BBBBB'
  6. ...

这就是一个简单的闭包例子,也是很多笔试题闭包实现数字累计的方法。

有的同学就会说 定义一个全局变量,底下函数直接给赋值就好了。这里只讲闭包不讲程序设计,为何要避免全局变量。要实现一个功能for 0-100循环不是也可以直接写100下。

知识梳理

  • 闭包产生的条件:函数内部函数作为返回值,并使用函数内的局部变量
  • 闭包的表现:所用的变量不被销毁,一直存在内存中 这就是闭包常说的 可以导致内存泄露 和 变量提升。这就是可以成为私有属性创建模式

应用案例

1.实现累加计数  这个例子和上面的差不多 只是有两个return 按上面的就很好理解了

  function fn() {
       var init = 0;
       return function () {
           init = init+1
           return init;
       }
   }
   var fun = fn();
   var add1 = fun();
   var add2 = fun();
   var add3= fun();
   var add4 = fun();
   console.log(add1);
   console.log(add2);
   console.log(add3);
   console.log(add4);

2.实现函数私有属性

1.   function book() {
2.       var page = 100;
3.       return function () {
4.           this.auther = 'wuy';
5.           this.price = 200;
6.           this._page = function () {
7.               return page
8.           }
9.       }
10.   }
11.   var books =  book();
12.   var cssbook = new books();
13.   console.log(cssbook._page());  //打印100
14.   console.log(cssbook.auther);   //打印wuy

简单分析一下

  1. 1-10行 先定义一个函数book ,函数,
  2. 11行 函数开始运行 执行 2-9行代码,定义一个page局部变量 返回返回值为一个函数 3-9行 返回的函数就用到了book内定义的page 闭包形成 page 一直存在内存中。
  3. 第12行 返回的函数 3-9行 是一个构造函数用new关键字声明成一个对象 赋值为cssbook;因此函数内部的this指向cssbook
  4. 第13行 打印cssbook的_page()这个方法的返回值  就是内存中的page  100 ;这就是函数的私有属性
  5. 第14行 打印cssbook的auther wuy

 

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值