• 匿名函数和闭包


    一、匿名函数

    匿名函数就是没有名字的函数,又称作Lambda函数。好多资料说它强大,它到底强大在哪

    1 function foo(arg1,arg2,arg3){
    2     //code  
    3 }
    4 
    5 var foo = function(arg1,arg2,arg3){
    6     //code  
    7 }

    这两者区别在哪?

      第一个我们称作是函数声明 ,声明方式无非就是数据类型名,后面接空格和一个变量,就跟C++中的 int a ,char *c一样

      第二个函数称作函数表达式,表达式就是类似于 var a = b + c,string = stringA + stringB等

      它们的区别就是函数声明会在代码执行以前记载到作用域中,后者是在代码执行到那一行的时候才会有定义,才会去查找 a ,string到底是什么东东。

      另一个重要的区别是,函数声明给函数定义了一个名字foo ,而函数表达式是创建了一个匿名函数,这个函数谁都无法调用,但是它将指针赋值给foo以后,foo就可以去调用这个函数。

      为什么要使用匿名函数,单单的函数声明难道不够吗?

    1 function foo(arg1,arg2){
    2     return function(arg3,arg4){
    3     //code
    4     }
    5 }

    函数执行结果返回的函数可以赋值给一个变量,或者以其他方式调用。在把函数当成值使用的情况下都可以使用匿名函数。

    note:arguments.callee指向一个正在执行的函数指针,arguments.callee.caller是执行当前函数的一个对象或者说一个环境。

    二、作用域链

      在讲闭包前,先说一下作用域链,

      执行环境:execution context

      每个函数在被调用时会创建自己的执行环境,当执行流进入这个函数时,函数的环境变会被推入到一个环境栈中。当函数执行之后,栈将其环境弹出,控制权返回给之前的执行环境(其实这个执行环境就是作用域链的具体化)。

      变量对象构成一个作用域链,作用域链保证了程序的按序正常运行

    三、闭包

    闭包是什么,闭包就是可以访问另一个函数作用域中变量的函数。

    一般来讲,当函数执行完毕之后,,局部的活动对象被销毁,,内存中只包含全局作用域。

    创建方式:

      就是在一个函数中创建另一个函数。

      在匿名函数从函数foo中返回后,它的作用域链被初始化为包含foo函数的活动对象和全局变量对象。这样匿名函数就可以访问在foo中定义的所有变量。跟重要的是foo函数执行完毕之后,他的活动对象时不会被销毁的,因为匿名函数的作用域链仍然引用这个活动对象。只有当匿名函数销毁后,foo的活动对象才会被销毁。

    使用范围:

      1.模仿块级作用域!

      何为块级作用域?就是在这个语句块中有定义,脱离了以后自动销毁!

      

    1 function foo(num){
    2     for(var i =0;i<count;i++){
    3         //console.log(i);  
    4     }  
    5      //var i;重新声明也没用
    6     
    7      alert(i); 
    8 }    

      如上,在C,C++,java又块级作用域的语言中,if ,for语句中的变量声明会在语句执行完后销毁,但是javascript会自动添加到当前的执行环境中。因此i为num,即使重新声明也会是num。因为它会对后续的声明视为不见。

      匿名函数可以用来模仿块级作用域来避免由于各种写法,本来不想定义的变量存在全局中,无法销毁的问题

    1 (function(){
    2     //块级作用域
    3 })();

      这种技术长在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。一般来说我们应该尽量减少向全局作用域中添加过多的变量和函数。在一个有很多开发人员共同参与的大型应用程序中,过多的全局变量和函数会导致命名冲突,而通过创建私有作用域,每个开发人员可以使用自己的变量, 不用担心搞坏全局作用域。

      2.静态私有变量的方法:

     1 (function(){
     2     var name = '';
     3     Person = function(value){
     4         name = value;
     5     }
     6     Person.prototype.getName = function(){
     7         console.log("name",name)
     8         return name;
     9     }
    10     Person.prototype.setName = function(value){
    11         name = value;
    12     }
    13 })();
    14 //静态变量只要有一个对象跟改,其他的都跟着更改
    15 var p1 = new Person("我是第一");
    16 var p2 = new Person('我是第二');
    17 p1.getName();   //我是第二
    18 p2.getName();   //我是第二
    19 
    20 p1.setName("我变了");
    21 p1.getName();   //我变了
    22 p2.getName();   //我变了

      3.模块模式初探:

    前面的模式是用于自定义类型创建私有变量和特权方法。而道格拉斯所说的模块模式(Module Pattern)则是为单例创建私有变量和特权方法。所谓的单例就是一个实例的对象。

      单例:

    1 var singleton = {
    2     name:value,
    3     method: function(){
    4 
    5     }           
    6 }

    模块通过为单例添加私有变量和方法使其增强。

    在Web App中,经常需要使用一个单例来管理应用程序级的信息,比如下面的模块管理器。

     1 //模块管理器
     2 var moduleManger = function(){
     3     var _count = 0;
     4     var _module = {};
     5     
     6     var get = function(key){
     7         return _module[key];
     8     }
     9     var set = function(key,value){
    10         _module[key] = value;
    11         _count ++;
    12     }
    13     //delete
    14     var remove = function(key){
    15         delete _module[key];  
    16         _count--;
    17     }
    18     return {
    19         get : get,
    20         set : set,
    21         add : add,
    22         remove : remove
    23     }
    24 }();

    简言之,如果你必须创建一个对象并以某些数据对其初始化,同时还要公布一些能够访问这些私有数据的方法, 就可以使用模块模式。以这种模式创建的每个实例都是Object实例,最终通过一个字面量来表示它。

    注:module pattern是javascript的一种高级设计模式,有时间更新。

    由于闭包会携带包含它的函数作用域,因此会比其他的函数占用更多的内存,不宜过多的使用,但是用的好的话还是非常值得推荐的。

      

  • 相关阅读:
    java.lang.NoClassDefFoundError: org.junit.runner.Runner
    SpringMVC 八大注解
    spring @autowired使用总结
    Git使用入门
    N21_栈的压入弹出序列。
    N20_包含min函数的栈
    N19_顺时针打印指针
    N17_判断树B是不是树A的子结构
    N16_合并两个排序链表
    N15_反转链表后,输出新链表的表头。
  • 原文地址:https://www.cnblogs.com/simplevoid/p/2857533.html
Copyright © 2020-2023  润新知