浅谈JavaScript的函数表达式(闭包)

 

  前文已经简单的介绍了函数的闭包。函数的闭包就是有权访问另一个函数作用域的函数,也就是函数内部又定义了一个函数。

1 var Super=function(num){
2                         var count=num;
3                         return function(){
4                             console.log(count);
5                         }
6                     }
7                     var result=Super(3);//此时result是一个函数
8                     result();//输出3

  上面的代码定义了一个函数Super,同时在Super函数内部又定义了一个匿名函数作为返回值。第七行调用Super函数,此时result是一个函数。第8行执行了result函数,输出为3。这就是闭包的体现,因为上面的Super函数已经执行结束,但是它的内部变量count的值依然没有被释放,count的还在被匿名函数引用,所以没有办法释放。如果要释放count,我们需要 result=null ,将null赋值给result。

  在前文已经介绍了函数的作用域链,当函数第一次被调用时会创建一个作用域链,并作用域链赋值给一个特殊的内部属性。在作用域链中,函数的外部函数的活动对象位于第二位,外部函数的外部函数的活动对象位于第三位,以此类推,全局变量的作用域链位于最底部。

 1 var count=2;
 2 console.log(count);//2
 3 count=3;
 4 console.log(count);//3
 5 var Super=function(num){
 6 var count=num;//作用域链第二位
 7 console.log(count);//1
 8 return function(){
 9 var count=5;//作用域链第一位
10 console.log(count);
11 }
12 }
13 var result= new Super(1);
14 result();//输出5

  上面的代码中,能够清晰地了解到变量的作用域。闭包函数的内部变量位于最顶端,全局变量位于最底部。

  在闭包中使用this对象也可能会导致一些问题,this对象是在函数运行时,基于函数的执行环境绑定的。在全局函数中,this指向window对象。而函数作为某个对象的方式调用时,this等于那个对象。不过匿名函数的执行环境具有全局性,因此this指向window

 1 var obj={
 2                         name:"heh",
 3                         getName:function(){
 4                             var that=this;
 5                             return function(){
 6                                 return that.name;
 7                             }
 8                         }
 9                     };
10                     var one=obj.getName();
11                     var name=one();//heh

  上面的代码中,通过字面量的方式创建了对象obj,定义了对象的属性name和方法getName。但是在getName内部,我们定义了闭包函数。如果想在闭包函数中访问name,通过this是访问不到的。所以需要在闭包函数的外部定义一个变量that,指向this。在getName中定义的变量,在闭包函数中仍然可以继续使用。

  JavaScript中没有块级作用域的概念,这意味着块级中定义的变量,实际在函数内部都是可以使用的。

1 for(var i=0;i<10;i++){
2                         console.log(i);
3                     }
4                     console.log(i);//输出10

  上面的代码中,我们在for循环中定义了变量i,但是我们在for循环外部依然可以使用i。for循环结束后,i变量并没有被销毁。

  JavaScript可以使用匿名函数来模仿块级作用域,从而避免该类问题的发生。

  

1 (function(){
2                         for(var i=0;i<10;i++){
3                             console.log(i);
4                         }
5                     })();
6                     console.log(i);

  上面的代码中,我们将块级作用域放在了一个匿名函数中,同时将匿名函数放在一对括号中,这表示一个函数表达式。在函数表达式外部的括号,表示立即调用该函数。在第六行调用该函数的时候,会发生报错,因为i并没有定义。

  

1 var testFunc=function(){
2                         for(var i=0;i<10;i++){
3                             console.log(i);
4                         }
5                     };
6                     testFunc();
7                     console.log(i);

  这个代码,和我们上面的代码是一样的,都是通过函数表达式来定义函数。

  

1 function(){
2                         for(var i=0;i<10;i++){
3                             console.log(i);
4                         }
5                     }();

  上面的代码是错误的。我们知道函数的定义方法,可以通过function和函数表达式。通过function声明函数的时候,function后面不能跟圆括号。函数表达式的后面可以跟圆括号。

  

1 var testFunc=function(){
2                         for(var i=0;i<10;i++){
3                             console.log(i);
4                         }
5                     }();

  一般来说在开发过程中,应该尽量少向全局对象中添加函数和变量。太多的全局函数和变量容易导致命名的冲突以及内存的泄露。我们可以在块级函数中完成所有的操作。

  

1 (function(){
2                         var now = new Date();
3                         console.log(now.getFullYear()+"-"+(now.getMonth()+1)+"-"+now.getDate()+" "+now.getHours()+":"+now.getMinutes()+":"+now.getSeconds());
4                     })();

  通过上面的代码,我们能够当前的日期和时间。

   

posted on 2018-02-09 16:19  水击三千  阅读(228)  评论(0编辑  收藏  举报

导航