匿名函數(shù)自執(zhí)行和閉包是一回事兒?jiǎn)幔?/h1>
一、匿名函數(shù)自執(zhí)行
概述
在javascript中,有些看起來(lái)很復(fù)雜卻又很好理解的東西,但是理解他們需要一定的技巧同時(shí)理解他們又非常的重要,了解了他們就給你打開(kāi)了一扇門,讓你知其然還能夠知其所以然。因?yàn)樗麄兙o密結(jié)合,自成一體。今天我們來(lái)說(shuō)說(shuō)這些既簡(jiǎn)單有重要的東西。
1.什么是函數(shù)表達(dá)式和函數(shù)聲明
大家已經(jīng)知道函數(shù)就是特殊的對(duì)象,然后大家也了解函數(shù)聲明和函數(shù)表達(dá)式了。
- //函數(shù)聲明
 - function show(){
 - console.log(12);
 - }
 - //函數(shù)表達(dá)式
 - var show = function(){
 - console.log(5);
 - };
 
2.看到函數(shù)表達(dá)式也沒(méi)啥奇怪的,因?yàn)楹瘮?shù)是對(duì)象,那把一個(gè)對(duì)象賦值給一個(gè)變量或者當(dāng)成參數(shù)傳遞都是可以的。
- //函數(shù)聲明
 - function show(){
 - console.log(12);
 - }
 - //函數(shù)表達(dá)式
 - var show = function(){
 - console.log(5);
 - };
 
函數(shù)能像數(shù)字一樣賦值給變量傳遞給參數(shù)的現(xiàn)象就叫做 first-class function,沒(méi)啥難的吧。
3.說(shuō)到了對(duì)象,我們就說(shuō)下引用和復(fù)制的區(qū)別。
- var a = 12;
 - var b = a;
 - b+=5;
 - alert(a);//12
 
這個(gè)沒(méi)啥好解釋的,b復(fù)制一份兒啊,b怎么改跟a無(wú)關(guān)。
- var arr1 = [12,5,8];
 - var arr2 = arr1;
 - arr2.pop();
 - alert(arr1);//12,5
 
我擦嘞,發(fā)生了什么?
記住一句話,基本類型的復(fù)制是直接拷貝一份兒跟原來(lái)的無(wú)關(guān),而對(duì)象復(fù)制僅僅是把地址指向復(fù)制了一份兒。
我有一個(gè)饅頭,基本類型復(fù)制就相當(dāng)于照著我的饅頭又給你做一個(gè),吃了你的饅頭我手里的沒(méi)影響。
我有一把鑰匙,能開(kāi)一個(gè)合租房的門,對(duì)象復(fù)制是引用,就是復(fù)制了一把鑰匙,你把廁所給拆了,我也得憋著。理解了不?
4.函數(shù)傳參這個(gè)我只是說(shuō)一句,這個(gè)是很多開(kāi)發(fā)者犯錯(cuò)的地方,這里不解釋我一解釋你上下都不明白了,只是告訴你就行。
訪問(wèn)變量有按值和按引用兩種方式,但是參數(shù)只能是按值傳遞。
參數(shù)類型是基本類型時(shí),被傳遞的值被復(fù)制給一個(gè)局部變量,而復(fù)合類型復(fù)制的是地址。
好吧,直接上一個(gè)例子吧。慢慢領(lǐng)悟吧。
- function setName(obj){
 - obj.name = "尼古拉斯·屌·大彬哥"
 - //重點(diǎn)
 - obj = new Object();
 - obj.name = "帥彬"
 - }
 - var Person = new Object();
 - setName(Person);
 - alert(Person.name);
 
5.關(guān)于函數(shù)的this和arguments
js里面最惡心的東西,沒(méi)有之一。下面我說(shuō)說(shuō)函數(shù)里面的this。
- function show(){console.log(this);}//window
 - var show = function{console.log(this);}//window
 
注意了,
- var person = {
 - name:"leo",
 - show:function(){
 - this.name = 'leolau';
 - console.log(this);//person對(duì)象 object
 - }
 - };
 
但是這里有個(gè)奇怪的事情,很多人認(rèn)為是bug,面試也經(jīng)??肌?/p>
- var person = {
 - name:"leo",
 - show:function(){
 - this.name = 'leolau';
 - console.log(this);//person對(duì)象 object
 - var bug = function(){
 - console.log(this);//window
 - }
 - bug();
 - }
 - };
 
如何解決?
- var person = {
 - name:"leo",
 - show:function(){
 - var that = this;
 - this.name = 'leolau';
 - console.log(this);//person對(duì)象 object
 - var bug = function(){
 - console.log(that);//person
 - }
 - bug();
 - }
 - };
 
至于arguments給大家一個(gè)實(shí)際應(yīng)用。未知參數(shù)個(gè)數(shù)不定求和。大家想想怎么做?
6.什么是匿名函數(shù)自執(zhí)行并如何在實(shí)際庫(kù)中應(yīng)用
匿名函數(shù)自執(zhí)行,注意,注意,只有這個(gè)名字和iife沒(méi)有其他名字,比如封閉空間,這個(gè)是為了讓大家好理解自己造的詞語(yǔ)。他的一個(gè)重要用途就是防止命名沖突,另外是組織和架構(gòu)庫(kù),比如jquery。
命名沖突
- a.js
 - var a = 12;
 - b.js
 - var a = 5;
 
同時(shí)引用a,b后面覆蓋前面了。怎么防止命名沖突前后覆蓋。
- var a = 12;
 - (function(){
 - var a = 5;
 - })();
 
這里iifes里面的a并不會(huì)干擾外面的a,那么問(wèn)題來(lái)了,萬(wàn)一我就想改外面的a,呢?
這也是很多jquery庫(kù)的做法,這么搞:
- (function(global,$){
 - $.a = 12;
 - global.a = 5;
 - })(window,jquery);
 
既滿足了外面的修改,又做到了防止變量污染。
二、閉包
概述
經(jīng)常聽(tīng)到閉包這個(gè)詞兒,或者匿名函數(shù)自執(zhí)行之類的。到底他們是一個(gè)東西嗎?
1.什么是閉包?
我不想扣定義,直接上例子。
- function parent(firstname){
 - return function(lastname){
 - console.log(firstname+'·屌·'+lastname);
 - }
 - }
 - parent('尼古拉斯')('大彬哥');
 
看圖:
函數(shù)執(zhí)行完以后會(huì)銷毀(這里我就不談堆棧操作了理解圖就行了),然后各種變量會(huì)垃圾回收,而這里parent函數(shù)確實(shí)銷毀了,但是firstName這個(gè)參數(shù)并沒(méi)有垃圾回收,釋放內(nèi)存,依然在內(nèi)存中能夠被return里面的函數(shù)使用,好像return里面的函數(shù)把父函數(shù)的那個(gè)資源給關(guān)閉在了自己的函數(shù)里面一樣,這個(gè)函數(shù)銷毀資源被關(guān)閉到子函數(shù)中依然能夠使用的現(xiàn)象叫做閉包。
注意匿名函數(shù)自執(zhí)行只是產(chǎn)生閉包的一種情況,閉包是現(xiàn)象或者情形,不實(shí)用匿名函數(shù)自執(zhí)行也有很多情況產(chǎn)生閉包,所以根本就是兩回事兒,不能混淆。
類比,在window系統(tǒng)中,你子文件夾中有使用的文件父文件夾是沒(méi)法刪除的。
2.實(shí)際應(yīng)用,情況很多,先來(lái)一道面試題。
- function fn{
 - var arr = [];
 - for(var i = 0;i<3;i++){
 - arr.push(function(){
 - console.log(i);
 - });
 - }
 - return arr;
 - }
 - var arrFn = fn();
 - arrFn[0]();//3
 - arrFn[1]();//3
 - arrFn[2]();//3
 
與這個(gè)類似的一個(gè)題是循環(huán)里面用事件,事件里面的i有問(wèn)題,如下。
- for(var i = 0;i<aBtn.length;i++){
 - aBtn[i].onclick = function(){
 - alert(i);//3
 - };
 - }
 
還有一到非常愛(ài)考的面試題:
- for(var i = 0;i<3;i++){
 - setTimeout(function(){
 - alert(i);
 - });
 - }
 
我只分析一個(gè),其它的大家就會(huì)分析了。注意表象上粗略的理解就是 函數(shù)執(zhí)行一瞬間,并不會(huì)等定時(shí)器,但是這個(gè)說(shuō)法并不對(duì),因?yàn)?**個(gè)就說(shuō)不通。下面我們進(jìn)入內(nèi)部深入分析下過(guò)程。
記住一句話,函數(shù)定義壓入arr的時(shí)候并沒(méi)有執(zhí)行。
小測(cè)驗(yàn),你能看出下面的程序用了閉包嗎?
- function show(){
 - var a = 12;
 - setTimeout(function(){
 - console.log(a);
 - },1000);
 - }
 
3.閉包在jquery中使用。
閉包無(wú)處不在,直接看jquery的例子。
- $('#btn').click(function(){
 - var json = {};
 - ajax(url,function(data){
 - json =dada;
 - });
 - });
 
【本文為51CTO專欄作者“面包理想學(xué)院”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)51CTO聯(lián)系作者獲取授權(quán)】

















 
 
 








 
 
 
 