微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

javascript闭包和立即执行函数的作用

转自:https://www.cnblogs.com/carriezhao/p/7237095.html

一、闭包——closure

  先看一个闭包的例子。我们想实现一个计数器,最简单的方法就是定义一个全局变量,计数的时候将其加1。但是全局变量有风险,哪里都有可能不小心改掉它。那局部变量呢,

它只在函数内部有效,函数调用完后它就没了,而且全局没法使用。那我们用想让计数器全局使用,又不想让这个变量被随便修改怎么办。这就需要闭包了:

1
2
3
4
5
6
function  count(){
     var  i=0;
     return  function  () {
         return  ++i;
     }
}   

  这个例子实现了一个简单的计数器。函数"count()"定义了一个局部变量“i”,并返回一个内部匿名函数。因为是内部函数,所以它可以访问其外部函数的局部变量“i”,并且将其加1并返回。让我们看下怎么使用这个计数器。

1
2
3
4
5
6
7
c1 = count();
console.log(c1());   //print1
console.log(c1());   //print2
console.log(c1());   //print3
 
c2 = count();
console.log(c2());   //print1

 每次调用“count()”函数后就会生成一个计数器,而且不同的计数器之间不干扰。因为两次调用一个函数,创建的栈是不同的,因此栈内的局部变量是不同的。上例中,我们生成了全局计数器“c1”和“c2”,他们都是不带参数的函数,即“count()”中返回的匿名函数。此后每次调用计数器,比如“c1()”,计数器就会自增1并返回。但是由于“count()”函数已经调用完毕,我们将无法通过任何其他办法去修改“count()”中变量“i”的值。这就是闭包最实用的功能,就是将你想操作的变量或对象隐藏起来,只允许特定的方法才能访问它

二、立即执行函数

  n年前看到jQuery的源码时,很好奇它的最外层结构是这样的(现在已经不一样了):var jQuery = (function(){……})();

  作为前端小白的我,实在想不通这是为什么,好好定义一个函数,为啥还要调用它。大家知道javascript在es6之前并不严格支持面向对象。js的对象其实就是一个map,比如下面的例子:

1
2
3
4
5
6
7
var  car = {
     speed:0,
     start: function (){  this .speed=40; },
     getspeed: function (){  return  this .speed; }
};
car.start();
console.log(car.getspeed());  //print 40

  这个对象有其成员变量“speed”及成员函数“start”和“getspeed”,但是它的成员变量没有私有化,同时它也没有办法被继承。要实现对象的继承,你可以使用构造函数和原型继承。但怎么才能将成员变量私有化来实现对象的封装呢(而且有时候我们也不想那么麻烦使用原型)?有心的读者看了上面闭包的介绍,肯定马上有想法了。对,使用闭包!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function  car() {
     var  speed = 0;
     return  //返回的是一个对象
         start: function () {
             speed = 50;
         },
     getspeed: function  () {
          return  speed;
         }
     }
}
 
var  car1 = car();
car1.start();
console.log(car1.getspeed());  //print 50

  说了那么多,跟立即执行函数有什么关系呢。你再仔细看看上面的例子,你有了闭包函数来帮你创建“car”对象,这个函数就类似于工厂方法,它可以根据你的需要创建多个不同的对象。不过开发的时候经常遇到这样的情况,就是我们希望对象只有一份,比如jQuery库的对象,它必须确保整个程序只有一份,多了也没有。在后端开发模式中,这叫单例模式,可以通过私有化构造函数来实现,那么在js里呢?

 

  既然函数没法私有化,那么唯一的办法就是让这个工厂方法能且只能被调用一次。不能多次调用,那这个函数一定要是匿名函数;而且能被调用一次,那就必须在声明的时候立马执行。这时候,我们就可以邀请立即执行函数出场了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var  car = ( function  () {
     var  speed = 0;
     return  {
         start: function  () {
             speed=60;
         },
         getspeed: function  () {
          return  speed;
         }
     }
})();
 
car.start();
console.log(car.getspeed());  //print 60                   

  很多人一开始会看错,认为对象“car”是一个函数,其实它是这个匿名的工厂方法执行完返回的对象,该对象拥有“start”和“getspeed”两个成员函数,而这两个函数所需要访问的“speed”变量对外不可见。同时你无法再次调用这个匿名的工厂方法来创建一个相同的对象。是不是很神奇?一个单例的,有着私有成员的对象就这么建好了。

  立即执行函数还有一种写法就是:

1
2
3
var  car = ( function  () {
     ……             
}());

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐