JavaScript: 零基礎(chǔ)輕松學(xué)閉包(2)

注:本人發(fā)布的所有文章均為原創(chuàng),未經(jīng)作者許可,切勿轉(zhuǎn)載,謝謝。

本文面向初學(xué)者,大神輕噴。

好了,開(kāi)始吧。

上一節(jié) JavaScript: 零基礎(chǔ)輕松學(xué)閉包(1)中,我們對(duì)閉包的原理進(jìn)行了講解,這一節(jié)會(huì)說(shuō)很多實(shí)戰(zhàn)性的東西了,可能會(huì)有點(diǎn)難度,你準(zhǔn)備好了嗎?

1. 如何將私有數(shù)據(jù)暴露出去

還記得在上一節(jié)中,有這樣一個(gè)例子么?

var test = function(){
    var i = 10;
}

function test2(){
    alert(i);
}

test2();

函數(shù) test 和 test2 各自形成一個(gè)閉包,兩個(gè)閉包之間無(wú)法訪(fǎng)問(wèn)對(duì)方的私有數(shù)據(jù)。比如,在 test 中定義的變量,在 test2 里面是無(wú)法直接訪(fǎng)問(wèn)到的。

那么問(wèn)題來(lái)了, 當(dāng)然,這邊和挖掘機(jī)沒(méi)關(guān)系。這里的問(wèn)題是,有沒(méi)有什么辦法讓 test2 可以訪(fǎng)問(wèn)到其他閉包中的私有變量呢?

辦法當(dāng)然是有的,最直接的想法就是,大不了我定義一個(gè)全局變量,在 test 中將私有數(shù)據(jù)賦給全局變量,然后在 test2 里面就能訪(fǎng)問(wèn)到了。

是的,因?yàn)閮蓚€(gè)函數(shù)共同享有一個(gè)全局作用域,所以這個(gè)辦法確實(shí)可行。我在很多項(xiàng)目里也的確看到很多人就是這么做的。

那么,有沒(méi)有一種更好的方法呢?要知道,全局作用域是一個(gè)比較敏感的地方,一不小心就會(huì)出現(xiàn)變量名重復(fù)的問(wèn)題。順便說(shuō)一句,在全局作用域中,盡量不要使用諸如 temp , a , b , c 這一類(lèi)的大眾化變量。

于是,這就牽扯到返回值的相關(guān)知識(shí)了,你在C語(yǔ)言的教材中肯定見(jiàn)慣了類(lèi)似于這樣的代碼

int sum(int a,int b)
{
    return a + b;
}

int all = sum(3,5);

這是一個(gè)簡(jiǎn)單的求和函數(shù),很多人慢慢地養(yǎng)成了這樣一個(gè)觀念,就是函數(shù)的返回值就是一個(gè)字面值,要么是數(shù)字類(lèi)型,要么是布爾類(lèi)型,或者是字符串。

在很多強(qiáng)類(lèi)型的語(yǔ)言,諸如 Java,C,C++, 確實(shí)如此。但是 return 在 JavaScript 中卻大有來(lái)頭。

在上一節(jié)已經(jīng)說(shuō)明了,js 的函數(shù)也是一種數(shù)據(jù)類(lèi)型,你可以把函數(shù)看成是和int , float , double 一樣的東西。

那么,既然int可以當(dāng)做函數(shù)的參數(shù)或者返回值,函數(shù)當(dāng)然也可以!

請(qǐng)看下面兩句話(huà):

在js中

  • 如果函數(shù)被當(dāng)做參數(shù)傳進(jìn)去了,它就是所謂的回調(diào)函數(shù)。
  • 如果函數(shù)被當(dāng)做返回值return出去了,它就是把一個(gè)閉包return出去了。

這一章不講回調(diào)函數(shù),如果你不清楚啥叫回調(diào)函數(shù),可以去看看這個(gè)小例子:
淺談js回調(diào)函數(shù)

還是上面的那個(gè)例子,我們希望在 test2 中可以訪(fǎng)問(wèn)到 test 里面的變量,可以這樣做:

var test = function(){
    var i = 10;
    /* 定義一個(gè)函數(shù)將變量i暴露出去  */
    var get = function(){
        return i ;
    }
    return get; //將獲得i的函數(shù)暴露出去
}

function test2(){
    
    var fn= test();//接收test暴露出來(lái)的函數(shù)
    alert(fn()); //獲得test中的私有數(shù)據(jù)
}

test2();
Paste_Image.png

test 函數(shù)中的 get 方法是一個(gè)內(nèi)部函數(shù),它自己也形成了一個(gè)閉包, test 是他的父級(jí)作用域,因此它可以獲取i的值。

i 進(jìn)入 get 方法的閉包,被包了起來(lái),然后最終被返回了出去。

而對(duì)于 test2 來(lái)說(shuō),是可以訪(fǎng)問(wèn)到 test函數(shù)的,因此可以調(diào)用并執(zhí)行 test 函數(shù),從而獲取其返回值。

你可能會(huì)說(shuō),我直接在test中把i給return出去就好了嘛,干嘛這么麻煩。

是的,言之有道理。

可是,如果我要訪(fǎng)問(wèn) test 中多個(gè)私有數(shù)據(jù)咋辦捏?

這下你可明白了吧!

現(xiàn)在,我們給出關(guān)于閉包的第二個(gè)注解:
(第一個(gè)注解在上一節(jié))

從應(yīng)用的角度來(lái)看,閉包可以將函數(shù)或者對(duì)象的私有數(shù)據(jù)暴露出去,而不影響全局作用域。
Paste_Image.png

通過(guò)這張圖,是不是好理解一些了呢?我們這一節(jié)單說(shuō)函數(shù)里的私有數(shù)據(jù)。

2. 將私有數(shù)據(jù)包裝成json對(duì)象

剛才的例子說(shuō)明,在js中,return出去的可以是基本數(shù)據(jù)類(lèi)型,也可以是函數(shù)類(lèi)型。

其實(shí),JavaScript是一種基于對(duì)象的語(yǔ)言,也有對(duì)象的概念,所以,我們可以把你需要的東西包裹成一個(gè)對(duì)象返回出去!

上代碼:

var test = function(){
    var apple = '蘋(píng)果';
    var pear = '梨子';
    /* 定義一個(gè)函數(shù)將水果暴露出去  */
    var getFruit = {
        apple : apple ,
        pear : pear
    }
   
    return getFruit; //將獲得i的函數(shù)暴露出去
}

function test2(){
    
    var getFruit = test();//接收test暴露出來(lái)的函數(shù)
    
    console.log(getFruit);
}

test2();

像這樣用 { } 括起來(lái)的東西就是一個(gè)js對(duì)象,也就是所謂json。你可能經(jīng)常會(huì)聽(tīng)到j(luò)son這個(gè)詞,覺(jué)得還挺高大上的。其實(shí)它就是一個(gè)用 { } 包起來(lái)的數(shù)據(jù)而已。

里面是鍵值對(duì)的形式,非常類(lèi)似于Java里面的HashMap。

在這個(gè)例子中,我們可以直接把需要暴露的私有數(shù)據(jù)用一個(gè) { } 包起來(lái),構(gòu)成一個(gè)json對(duì)象return出去就可以啦。

因?yàn)槭?js 對(duì)象,alert 不能看到里面的具體內(nèi)容,所以我們使用 console.log() ,結(jié)果如下:

Paste_Image.png

展開(kāi)后:

Paste_Image.png

這樣是不是也可以了?多出來(lái)的 proto 是原型鏈,以后會(huì)講到。

3. 我們來(lái)做一個(gè)紫金葫蘆

大家都還記得西游記里孫悟空用遮天的把戲騙來(lái)的紫金葫蘆嗎,只要你拿著這個(gè)葫蘆,叫一聲別人的名字,如果答應(yīng)了,別人就會(huì)被吸進(jìn)去。

OK,這個(gè)紫金葫蘆里面不正如一個(gè)閉包嗎?

對(duì)不對(duì)嘛,所以,我們用閉包的知識(shí)來(lái)做一個(gè)好玩的東西吧。

<body>
    <div id='box' style='width:50px;height:50px;background:#333;color:#fff;text-align:center;line-height:50px'>小妖</div>
</body>
Paste_Image.png

紫金葫蘆里面的源碼大概是這樣的:

var 紫金葫蘆 = function(id){
    var domElement = document.getElementById(id);
    
    var returnObject = {

        domElement : domElement ,

        backgroundColor : function(color){
            domElement.style.backgroundColor = color;
        },

        click : function(fn){
            domElement.onclick = fn;
        }
    };
    
    return returnObject;
}

注:我純粹是為了看起來(lái)方便而采用中文定義變量,在實(shí)際開(kāi)發(fā)中,千萬(wàn)不要使用中文變量。

我們?cè)诜祷爻鋈サ膶?duì)象上加了三個(gè)東西:

1.domElement
你傳進(jìn)來(lái)一個(gè)id,我就用 document.getElementById 來(lái)包一下,得到一個(gè)dom元素,最終要操作的也就是這個(gè)dom元素。也就是說(shuō):

var box1 = 紫金葫蘆('box').domElement;
var box2 = document.getElementById('box');
alert(box1 === box2);
Paste_Image.png

他們是一個(gè)東西,一樣的。

紫金葫蘆('box');

這行代碼一旦執(zhí)行,紫金葫蘆就會(huì)返回 returnObject 對(duì)象,也就是說(shuō)。我們喊一聲 “box”,那個(gè)id為box的小妖一答應(yīng),就被裝進(jìn)來(lái)了,然后我們可以對(duì)它為所欲為!

比如,給它換一個(gè)背景色:

2.backgroundColor 給元素添加背景色的方法

var box = 紫金葫蘆('box');
box.backgroundColor('red');
Paste_Image.png

3.click 給元素添加點(diǎn)擊事件,需要傳入一個(gè)回調(diào)函數(shù)

var box = 紫金葫蘆('box');
box.click(function(){
    alert('就沒(méi)人吐槽這個(gè)無(wú)聊的作者么,小妖也有尊嚴(yán)的好么,啊喂!!');
});

結(jié)果:

click.gif

也許你已經(jīng)發(fā)現(xiàn)了,這些方法是不是和jQuery有點(diǎn)類(lèi)似呢?

本章結(jié)束 ...

剽悍一小兔,電氣自動(dòng)化畢業(yè)。
參加工作后對(duì)計(jì)算機(jī)感興趣,深知初學(xué)編程之艱辛。
希望將自己所學(xué)記錄下來(lái),給初學(xué)者一點(diǎn)幫助。

免責(zé)聲明: 博客中所有的圖片素材均來(lái)自百度搜索,僅供學(xué)習(xí)交流,如有問(wèn)題請(qǐng)聯(lián)系我,侵立刪,謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容