匿名函数自执行和闭包是一回事儿吗?

开发 开发工具
在javascript中,有些看起来很复杂却又很好理解的东西,但是理解他们需要一定的技巧同时理解他们又非常的重要,了解了他们就给你打开了一扇门,让你知其然还能够知其所以然。因为他们紧密结合,自成一体。今天我们来说说这些既简单有重要的东西。

 一、匿名函数自执行

概述

在javascript中,有些看起来很复杂却又很好理解的东西,但是理解他们需要一定的技巧同时理解他们又非常的重要,了解了他们就给你打开了一扇门,让你知其然还能够知其所以然。因为他们紧密结合,自成一体。今天我们来说说这些既简单有重要的东西。

1.什么是函数表达式和函数声明

 大家已经知道函数就是特殊的对象,然后大家也了解函数声明和函数表达式了。

  1. //函数声明 
  2.         function show(){ 
  3.             console.log(12); 
  4.         } 
  5.          
  6.      //函数表达式 
  7.         var show = function(){ 
  8.             console.log(5); 
  9.         };    

2.看到函数表达式也没啥奇怪的,因为函数是对象,那把一个对象赋值给一个变量或者当成参数传递都是可以的。

  1. //函数声明 
  2.         function show(){ 
  3.             console.log(12); 
  4.         } 
  5.          
  6.      //函数表达式 
  7.         var show = function(){ 
  8.             console.log(5); 
  9.         };    

函数能像数字一样赋值给变量传递给参数的现象就叫做 first-class function,没啥难的吧。

3.说到了对象,我们就说下引用和复制的区别。

  1. var a = 12; 
  2. var b = a; 
  3. b+=5; 
  4. alert(a);//12 

这个没啥好解释的,b复制一份儿啊,b怎么改跟a无关。

  1. var arr1 = [12,5,8]; 
  2. var arr2 = arr1; 
  3. arr2.pop(); 
  4. alert(arr1);//12,5 

我擦嘞,发生了什么?

记住一句话,基本类型的复制是直接拷贝一份儿跟原来的无关,而对象复制仅仅是把地址指向复制了一份儿。

我有一个馒头,基本类型复制就相当于照着我的馒头又给你做一个,吃了你的馒头我手里的没影响。

我有一把钥匙,能开一个合租房的门,对象复制是引用,就是复制了一把钥匙,你把厕所给拆了,我也得憋着。理解了不?

4.函数传参这个我只是说一句,这个是很多开发者犯错的地方,这里不解释我一解释你上下都不明白了,只是告诉你就行。

访问变量有按值和按引用两种方式,但是参数只能是按值传递。

参数类型是基本类型时,被传递的值被复制给一个局部变量,而复合类型复制的是地址。

好吧,直接上一个例子吧。慢慢领悟吧。

  1. function setName(obj){ 
  2.   obj.name = "尼古拉斯·屌·大彬哥" 
  3.   //重点 
  4.   obj = new Object(); 
  5.   obj.name = "帅彬" 
  6. var Person = new Object(); 
  7. setName(Person); 
  8. alert(Person.name); 

5.关于函数的this和arguments

js里面最恶心的东西,没有之一。下面我说说函数里面的this。

  1. function show(){console.log(this);}//window 
  2. var show = function{console.log(this);}//window 

注意了,

  1. var person = { 
  2.         name:"leo"
  3.         show:function(){ 
  4.             this.name = 'leolau';  
  5.             console.log(this);//person对象 object 
  6.         } 
  7. }; 

但是这里有个奇怪的事情,很多人认为是bug,面试也经常考。

  1. var person = { 
  2.         name:"leo"
  3.         show:function(){ 
  4.             this.name = 'leolau';  
  5.             console.log(this);//person对象 object 
  6.              var bug = function(){ 
  7.             console.log(this);//window 
  8.             } 
  9.             bug(); 
  10.         }    
  11. }; 

如何解决?

  1. var person = { 
  2.         name:"leo"
  3.         show:function(){ 
  4.             var that = this; 
  5.             this.name = 'leolau';  
  6.             console.log(this);//person对象 object 
  7.              var bug = function(){ 
  8.             console.log(that);//person 
  9.             } 
  10.             bug(); 
  11.         }    
  12. }; 

至于arguments给大家一个实际应用。未知参数个数不定求和。大家想想怎么做?

6.什么是匿名函数自执行并如何在实际库中应用

匿名函数自执行,注意,注意,只有这个名字和iife没有其他名字,比如封闭空间,这个是为了让大家好理解自己造的词语。他的一个重要用途就是防止命名冲突,另外是组织和架构库,比如jquery。

命名冲突

  1. a.js 
  2. var a = 12; 
  3. b.js 
  4. var a = 5; 

同时引用a,b后面覆盖前面了。怎么防止命名冲突前后覆盖。

  1. var a = 12; 
  2. (function(){ 
  3.     var a = 5; 
  4. })(); 

这里iifes里面的a并不会干扰外面的a,那么问题来了,万一我就想改外面的a,呢?

这也是很多jquery库的做法,这么搞:

  1. (function(global,$){ 
  2.     $.a = 12; 
  3.     global.a = 5; 
  4.    
  5. })(window,jquery); 

既满足了外面的修改,又做到了防止变量污染。

二、闭包

概述

经常听到闭包这个词儿,或者匿名函数自执行之类的。到底他们是一个东西吗?

1.什么是闭包?

 我不想扣定义,直接上例子。

  1. function parent(firstname){ 
  2.   return function(lastname){ 
  3.   console.log(firstname+'·屌·'+lastname); 
  4.   } 
  5. parent('尼古拉斯')('大彬哥'); 

看图:

函数执行完以后会销毁(这里我就不谈堆栈操作了理解图就行了),然后各种变量会垃圾回收,而这里parent函数确实销毁了,但是firstName这个参数并没有垃圾回收,释放内存,依然在内存中能够被return里面的函数使用,好像return里面的函数把父函数的那个资源给关闭在了自己的函数里面一样,这个函数销毁资源被关闭到子函数中依然能够使用的现象叫做闭包。

注意匿名函数自执行只是产生闭包的一种情况,闭包是现象或者情形,不实用匿名函数自执行也有很多情况产生闭包,所以根本就是两回事儿,不能混淆。

类比,在window系统中,你子文件夹中有使用的文件父文件夹是没法删除的。

2.实际应用,情况很多,先来一道面试题。

  1. function fn{ 
  2.             var arr = []; 
  3.             for(var i = 0;i<3;i++){ 
  4.                 arr.push(function(){ 
  5.                     console.log(i); 
  6.                 }); 
  7.             } 
  8.             return arr; 
  9.         } 
  10.         var arrFn = fn(); 
  11.         arrFn[0]();//3 
  12.         arrFn[1]();//3 
  13.         arrFn[2]();//3 

与这个类似的一个题是循环里面用事件,事件里面的i有问题,如下。

  1. for(var i = 0;i<aBtn.length;i++){ 
  2.     aBtn[i].onclick = function(){ 
  3.         alert(i);//3 
  4.     }; 

还有一到非常爱考的面试题:

  1. for(var i = 0;i<3;i++){ 
  2.     setTimeout(function(){ 
  3.         alert(i); 
  4.     }); 

我只分析一个,其它的大家就会分析了。注意表象上粗略的理解就是 函数执行一瞬间,并不会等定时器,但是这个说法并不对,因为***个就说不通。下面我们进入内部深入分析下过程。

记住一句话,函数定义压入arr的时候并没有执行。

小测验,你能看出下面的程序用了闭包吗?

  1. function show(){ 
  2.     var a = 12; 
  3.     setTimeout(function(){ 
  4.         console.log(a); 
  5.     },1000); 

3.闭包在jquery中使用。

闭包无处不在,直接看jquery的例子。

  1. $('#btn').click(function(){ 
  2.     var json = {}; 
  3.     ajax(url,function(data){ 
  4.         json =dada; 
  5.     }); 
  6.      
  7. }); 

【本文为51CTO专栏作者“面包理想学院”的原创稿件,转载请通过51CTO联系作者获取授权】

戳这里,看该作者更多好文

 

责任编辑:武晓燕 来源: 51CTO专栏
相关推荐

2023-05-31 16:40:01

2017-10-11 13:20:36

2019-12-06 10:44:27

分布式集群业务

2023-01-06 11:08:51

MPP架构Hadoop

2021-11-02 09:50:37

MPPHadoop架构

2019-07-25 06:52:21

物联网大数据物联网即服务

2022-09-19 23:55:59

深度学习统计学人工智能

2020-05-07 09:02:55

代码Python开发

2023-05-22 16:33:03

数字化转型数据管理数字化

2020-08-12 09:10:16

AI芯片AI人工智能

2019-10-12 10:40:32

区块链数字货币比特币

2017-03-24 18:38:40

互联网

2016-07-19 14:51:16

比特率波特率比特位

2019-12-24 11:19:44

容器DockerLinux

2017-03-24 17:55:47

互联网

2022-08-14 15:01:21

芯片禁令

2021-11-26 10:48:06

MPPHadoop数据库

2017-05-11 12:22:10

2018-05-08 08:46:47

Linux内存释放

2021-01-06 20:38:09

VRARMR
点赞
收藏

51CTO技术栈公众号