技术干货程序员让前端飞

JavaScript专题(二)我眼中的闭包

2017-04-06  本文已影响0人  海客无心

我花了好长的时间,看了网上好多的博客才理解了(自以为)闭包的意义。
我分以下几点来讲闭包:




1.俯视闭包:

假装写代码:

          过去,我在写代码,我是用二进制写的,我只知道0和1;
          如今,我在写代码,我用的是记事本,我知道abcd;
          未来,我在写代码,也许我根本不用学JS???一呼一吸就是法则?

闭包定义:

闭包是指有权访问另一个函数作用域中的变量的函数。

翻译:在今天,我可以不知道函数内部是怎么样运行的,它们已经被封装在了函数里,被语法所定义了,我只要知道toString()就是返回字符串就行了。这其实就是闭包。

我只要知道我能通过某种方式获取信息就行了。这种方式就是闭包。

function 科技发展(){           //现代版
  var 内部编译原理=xxx;
  return function 使用方法(莫须有的参数){
              通过xxx,你想做什么都可以;
 }
}
var 我要使用科技=科技发展();
我要使用科技(莫须有的参数);          
//就这样,我可以不懂(无法直接获取)xxx,但我懂使用(获取)方法就可以了

学过C++或者相似语言的还可发现,这跟类的私有变量很像对吧。我们可以用接口函数获取,但不能直接获取。

(1)闭包是一种设计原则,它通过分析上下文,来简化用户的调用,让用户在不知晓的情况下,达到他的目的;
(2)网上主流的对闭包剖析的文章实际上是和闭包原则反向而驰的,如果需要知道闭包细节才能用好的话,这个闭包是设计失败的;
(3)尽量少学习。 -------http://kb.cnblogs.com/page/110782/

其实,我们可以从两方面的角度看闭包。
----------a.从设计者的角度上,用户没法直接获得数据,其实也就是实现了数据的私有。
----------b.从使用者的角度上,用户可以通过另外的方式(这个方式也许更加简单、方 便,具体根据设计者来定)获得数据或者甚至操作封装好了的数据。

END.
想继续学请看下方。















2.变量的一生:

所以如果你要销毁变量,如果是全局变量,那么你需要覆盖它,如果是局部变量你只要等待它所在的方法结束,它就自动销毁了。
function test(){var a=3;}

    alert(a);   //error,a 已经被销毁了
    for(var a=3;a<10;a++){}
    alert(a);  // 输出10,因为a在全局中定义,还没有被销毁

虽然在外部没法输出a,这是因为没法访问,但a还是存在于内存之中。因为内部的函数引用了外部的变量a(引用计数法垃圾清除,为0则删除),所以a还被人惦记着,自然也不会消亡。

3.匿名函数:
function I_have_name(){//do something}   
 //它就是有名字的函数,它的名字叫做   "I_have_name"
function (){//do something}              
 //它是匿名函数,它没有定义名字
(function (){
alert(3);
})();               //它就是自执行函数
(function auto(){
alert(3);
})();             //它也是自执行函数,效果同上
                    //也就是说那个auto没有卵用?(此句是版主自以为的)
//--------------------------------------------------
//此处还有一个坑,那就是如果
function(){
alert(3);
}();                //这样写是错的!!!!!!!!!!!!!!

为什么(function {// code})();可以被执行, 而function {// code}();却会报错?
答:
1.我们来看他们的区别,其实前者它叫函数声明,而后者它叫函数表达式。
2.JS的预编译的时候我先看函数声明,忽略函数表达式。就像给声明开了个后门一样。
3.当JS正式编译的时候,声明过的函数看到了(function{//code}就跳过了,因为它编译过了,所以,他只会看到()这个东西。???这个是什么玩意儿,于是函数就报错了。
4.而匿名函数还是完整的,所以能够正常执行。
5.还需要知道的是,自执行函数的标识可以是

!function(){}()              (function(){})()    
~function(){}()      void function(){}()

6.自执行函数是可以带参数的,格式是这样的!

function(num){
alert(num);
}(3);                  输出3
4.闭包陷阱

然后我们来说一个常见的闭包例子,这是一个闭包的副作用。

var arr=[1,2,3];
  var obj={};
  var test=function(){
      for(var i=0;i<arr.length;i++)
      {
          obj[i]=function(){
              alert(i);
          }
      }
  }

  test();
  for(var i=0;i<arr.length;i++)
  {
      obj[i]();             //最后的输出是输出了三个3.
  }

按照正常的思维,最后应该是obj[0]=0,obj[1]=1,obj[2]=2,但是真正的过程是这样的:


var test=function(){
      for(var i=0;i<arr.length;i++)
      {
          obj[i]=function(canshu){
              alert(canshu);
          }(i);
      }
}
test();
  for(var i=0;i<arr.length;i++)
  {
      obj[i]();             //最后分别输出:0,1,2   达成预期
  }

如果你看懂了上面的,你就明白了。
对!我使用了匿名函数!一个带参数的匿名函数。这里的(i),是在外围的区域里面的,跟obj[i]中i一模一样,而作为内部函数里,它是被赋值(或者我们还可以说是复制)给canshu,所以,它是即时按值传递的!!!
(PS:自己发明的词语,仅供参考,主要的问题在于,我不知道底层到底是如何运行的,说它是引用又觉得不太对劲)

这个过程的实现也成功避免了闭包带来的陷阱。

5. 审视闭包:

其实我们甚至可以说,在全局环境中写的function,都是一个闭包。


参考文献
1.超级推荐的文章
2.什么是闭包,闭包的优缺点
3.Javascript闭包——懂不懂由你,反正我是懂了
4.浅析匿名函数

上一篇 下一篇

猜你喜欢

热点阅读