補(bǔ)充:
閉包(closure)是Javascript語(yǔ)言的一個(gè)難點(diǎn),也是它的特色,很多高級(jí)應(yīng)用都要依靠閉包實(shí)現(xiàn)。
閉包的特性
閉包有三個(gè)特性:
1.函數(shù)嵌套函數(shù)
2.函數(shù)內(nèi)部可以引用外部的參數(shù)和變量
3.參數(shù)和變量不會(huì)被垃圾回收機(jī)制回收
閉包的定義及其優(yōu)缺點(diǎn)
閉包 是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù),創(chuàng)建閉包的最常見的方式就是在一個(gè)函數(shù)內(nèi)創(chuàng)建另一個(gè)函數(shù),通過(guò)另一個(gè)函數(shù)訪問這個(gè)函數(shù)的局部變量
閉包的缺點(diǎn)就是常駐內(nèi)存,會(huì)增大內(nèi)存使用量,使用不當(dāng)很容易造成內(nèi)存泄露。
閉包是javascript語(yǔ)言的一大特點(diǎn),主要應(yīng)用閉包場(chǎng)合主要是為了:設(shè)計(jì)私有的方法和變量。
一般函數(shù)執(zhí)行完畢后,局部活動(dòng)對(duì)象就被銷毀,內(nèi)存中僅僅保存全局作用域。但閉包的情況不同!
圍著主題展開話題
1. 閉包的定義?
來(lái)看一些關(guān)于閉包的定義:
1.閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中變量的函數(shù)
2.函數(shù)對(duì)象可以通過(guò)作用域鏈相關(guān)聯(lián)起來(lái),函數(shù)體內(nèi)部的變量都可以保存在函數(shù)作用域內(nèi),這種特性稱為 ‘閉包' 。
3.內(nèi)部函數(shù)可以訪問定義它們的外部函數(shù)的參數(shù)和變量(除了this和arguments)。
大家想系統(tǒng)的學(xué)習(xí)js閉包的概念可以參考武林網(wǎng)網(wǎng)站的js電子書欄目學(xué)習(xí)吧。
來(lái)個(gè)定義總結(jié)
1.可以訪問外部函數(shù)作用域中變量的函數(shù)
2.被內(nèi)部函數(shù)訪問的外部函數(shù)的變量可以保存在外部函數(shù)作用域內(nèi)而不被回收---這是核心,后面我們遇到閉包都要想到,我們要重點(diǎn)關(guān)注被閉包引用的這個(gè)變量。
來(lái)創(chuàng)建個(gè)簡(jiǎn)單的閉包
var sayName = function(){var name = 'jozo';return function(){alert(name);}};var say = sayName(); say();
來(lái)解讀后面兩個(gè)語(yǔ)句:
•var say = sayName() :返回了一個(gè)匿名的內(nèi)部函數(shù)保存在變量say中,并且引用了外部函數(shù)的變量name,由于垃圾回收機(jī)制,sayName函數(shù)執(zhí)行完畢后,變量name并沒有被銷毀。
•say() :執(zhí)行返回的內(nèi)部函數(shù),依然能訪問變量name,輸出 'jozo' .
2. 閉包中的作用域鏈
理解作用域鏈對(duì)理解閉包也很有幫助。
變量在作用域中的查找方式應(yīng)該都很熟悉了,其實(shí)這就是順著作用域鏈往上查找的。
當(dāng)函數(shù)被調(diào)用時(shí):
1.先創(chuàng)建一個(gè)執(zhí)行環(huán)境(execution context),及相應(yīng)的作用域鏈;
2.將arguments和其他命名參數(shù)的值添加到函數(shù)的活動(dòng)對(duì)象(activation object)
作用域鏈:當(dāng)前函數(shù)的活動(dòng)對(duì)象優(yōu)先級(jí)最高,外部函數(shù)的活動(dòng)對(duì)象次之,外部函數(shù)的外部函數(shù)的活動(dòng)對(duì)象依次遞減,直至作用域鏈的末端--全局作用域。優(yōu)先級(jí)就是變量查找的先后順序;
先來(lái)看個(gè)普通的作用域鏈:
function sayName(name){return name;}var say = sayName('jozo');
這段代碼包含兩個(gè)作用域:a.全局作用域;b.sayName函數(shù)的作用域,也就是只有兩個(gè)變量對(duì)象,當(dāng)執(zhí)行到對(duì)應(yīng)的執(zhí)行環(huán)境時(shí),該變量對(duì)象會(huì)成為活動(dòng)對(duì)象,并被推入到執(zhí)行環(huán)境作用域鏈的前端,也就是成為優(yōu)先級(jí)最高的那個(gè)。 看圖說(shuō)話:
這圖在JS高級(jí)程序設(shè)計(jì)書上也有,我重新繪了遍。
在創(chuàng)建sayName()函數(shù)時(shí),會(huì)創(chuàng)建一個(gè)預(yù)先包含變量對(duì)象的作用域鏈,也就是圖中索引為1的作用域鏈,并且被保存到內(nèi)部的[[Scope]]屬性中,當(dāng)調(diào)用sayName()函數(shù)的時(shí)候,會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境,然后通過(guò)復(fù)制函數(shù)的[[Scope]]屬性中的對(duì)象構(gòu)建起作用域鏈,此后,又有一個(gè)活動(dòng)對(duì)象(圖中索引為0)被創(chuàng)建,并被推入執(zhí)行環(huán)境作用域鏈的前端。
一般來(lái)說(shuō),當(dāng)函數(shù)執(zhí)行完畢后,局部活動(dòng)對(duì)象就會(huì)被銷毀,內(nèi)存中僅保存全局作用域。但是,閉包的情況又有所不同 :
再來(lái)看看看閉包的作用域鏈:
function sayName(name){return function(){return name;}}var say = sayName('jozo');
這個(gè)閉包實(shí)例比上一個(gè)例子多了一個(gè)匿名函數(shù)的作用域:
在匿名函數(shù)從sayName()函數(shù)中被返回后,它的作用域鏈被初始化為包含sayName()函數(shù)的活動(dòng)對(duì)象和全局變量對(duì)象。這樣,匿名函數(shù)就可以訪問在sayName()中定義的所有變量和參數(shù),更為重要的是,sayName()函數(shù)在執(zhí)行完畢后,其活動(dòng)對(duì)象也不會(huì)被銷毀,因?yàn)槟涿瘮?shù)的作用域鏈依然在引用這個(gè)活動(dòng)對(duì)象,換句話說(shuō),sayName()函數(shù)執(zhí)行完后,其執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀,但他的活動(dòng)對(duì)象會(huì)留在內(nèi)存中,知道匿名函數(shù)會(huì)銷毀。這個(gè)也是后面要講到的內(nèi)存泄露的問題。
作用域鏈問題不寫那么多了,寫書上的東西也很累 o( 主站蜘蛛池模板: 枣庄市| 宁陕县| 勐海县| 瓮安县| 九寨沟县| 靖远县| 丽水市| 离岛区| 云浮市| 通道| 灵璧县| 惠来县| 福建省| 兴宁市| 茂名市| 合水县| 廊坊市| 南涧| 平乐县| 万宁市| 浮山县| 永康市| 波密县| 盐山县| 东辽县| 鹤峰县| 江孜县| 巴塘县| 普宁市| 金川县| 扶沟县| 江陵县| 安泽县| 厦门市| 荃湾区| 苏尼特左旗| 敖汉旗| 阜康市| 涿州市| 文登市| 玉溪市|