成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

javascript閉包是作用域嗎

在javascript中,閉包不是作用域,而是一個(gè)能夠持續(xù)存在的函數(shù)上下文活動(dòng)對(duì)象,是同時(shí)含有對(duì)函數(shù)對(duì)象以及作用域?qū)ο笠玫膶?duì)象。閉包主要是用來獲取作用域鏈或原型鏈上的變量或值。

javascript閉包是作用域嗎

本教程操作環(huán)境:windows7系統(tǒng)、javascript1.8.5版、Dell G3電腦。

我們知道,作用域鏈查找標(biāo)識(shí)符的順序是從當(dāng)前作用域開始一級(jí)一級(jí)往上查找。因此,通過作用域鏈,JavaScript 函數(shù)內(nèi)部可以讀取函數(shù)外部的變量,但反過來,函數(shù)的外部通常則無法讀取函數(shù)內(nèi)部的變量。在實(shí)際應(yīng)用中,有時(shí)需要在函數(shù)外部訪問函數(shù)的局部變量,此時(shí)最常用的方法就是使用閉包。

閉包是 JavaScript 的重要特性之一,在函數(shù)式編程中有著重要的作用,本節(jié)介紹閉包的結(jié)構(gòu)和基本用法。

那么什么是閉包?

閉包是一個(gè)能夠持續(xù)存在的函數(shù)上下文活動(dòng)對(duì)象,是同時(shí)含有對(duì)函數(shù)對(duì)象以及作用域?qū)ο笠玫膶?duì)象。閉包主要是用來獲取作用域鏈或原型鏈上的變量或值。創(chuàng)建閉包最常用的方式是在一個(gè)函數(shù)中聲明內(nèi)部函數(shù)(也稱嵌套函數(shù)),并返回內(nèi)部函數(shù)。

此時(shí)在函數(shù)外部就可以通過調(diào)用函數(shù)得到內(nèi)部函數(shù),進(jìn)而調(diào)用內(nèi)部函數(shù)來實(shí)現(xiàn)對(duì)函數(shù)局部變量的訪問。此時(shí)的內(nèi)部函數(shù)就是一個(gè)閉包。雖然按照閉包的概念,所有訪問了外部變量的 JavaScript 函數(shù)都是閉包,但我們平常絕大部分時(shí)候所謂的閉包其實(shí)指的就是內(nèi)部函數(shù)閉包。

閉包可以將一些數(shù)據(jù)封裝為私有屬性以確保這些變量的安全訪問,這個(gè)功能給應(yīng)用帶來了極大的好處。需要注意的是,閉包如果使用不當(dāng),也會(huì)帶來一些意想不到的問題。下面就通過幾個(gè)示例來演示一下閉包的創(chuàng)建、使用和可能存在的問題及其解決方法。

形成原理

函數(shù)被調(diào)用時(shí),會(huì)產(chǎn)生一個(gè)臨時(shí)上下文活動(dòng)對(duì)象。它是函數(shù)作用域的頂級(jí)對(duì)象,作用域內(nèi)所有私有方法有變量、參數(shù)、私有函數(shù)等都將作為上下文活動(dòng)對(duì)象的屬性而存在。

函數(shù)被調(diào)用后,在默認(rèn)情況下上下文活動(dòng)對(duì)象會(huì)被立即釋放,避免占用系統(tǒng)資源。但是,若函數(shù)內(nèi)的私有變量、參數(shù)、私有函數(shù)等被外界引用,則這個(gè)上下文活動(dòng)對(duì)象暫時(shí)會(huì)繼續(xù)存在,直到所有外界引用被注銷。

但是,函數(shù)作用域是封閉的,外界無法訪問。那么在什么情況下,外界可以訪問到函數(shù)內(nèi)的私有成員呢?

根據(jù)作用域鏈,內(nèi)部函數(shù)可以訪問外部函數(shù)的私有成員。如果內(nèi)部函數(shù)引用了外部函數(shù)的私有成員,同時(shí)內(nèi)部函數(shù)又被傳給外界,或者對(duì)外界開放,那么閉包體就形成了。這個(gè)外部函數(shù)就是一個(gè)閉包體,它被調(diào)用后,活動(dòng)對(duì)象暫時(shí)不會(huì)被注銷,其屬性會(huì)繼續(xù)存在,通過內(nèi)部函數(shù)可以持續(xù)讀寫外部函數(shù)的私有成員。

閉包結(jié)構(gòu)

典型的閉包體是一個(gè)嵌套結(jié)構(gòu)的函數(shù)。內(nèi)部函數(shù)引用外部函數(shù)的私有成員,同時(shí)內(nèi)部函數(shù)又被外界引用,當(dāng)外部函數(shù)被調(diào)用后,就形成了閉包。這個(gè)函數(shù)也稱為閉包函數(shù)。

下面是一個(gè)典型的閉包結(jié)構(gòu)。

function f(x) {  //外部函數(shù)     return function (y) {  //內(nèi)部函數(shù),通過返回內(nèi)部函數(shù),實(shí)現(xiàn)外部引用         return x + y;  //訪問外部函數(shù)的參數(shù)     }; } var c = f(5);  //調(diào)用外部函數(shù),獲取引用內(nèi)部函數(shù) console.log(c(6));  //調(diào)用內(nèi)部函數(shù),原外部函數(shù)的參數(shù)繼續(xù)存在

解析過程簡單描述如下:

  • 在 JavaScript 腳本預(yù)編譯期,聲明的函數(shù) f 和變量 c,先被詞法預(yù)解析。

  • 在 JavaScript 執(zhí)行期,調(diào)用函數(shù) f,并傳入值 5。

  • 在解析函數(shù) f 時(shí),將創(chuàng)建執(zhí)行環(huán)境(函數(shù)作用域)和活動(dòng)對(duì)象,并把參數(shù)和私有變量、內(nèi)部函數(shù)都映射為活動(dòng)對(duì)象的屬性。

  • 參數(shù) x 的值為 5,映射到活動(dòng)對(duì)象的 x 屬性。

  • 內(nèi)部函數(shù)通過作用域鏈引用了參數(shù) x,但是還沒有被執(zhí)行。

  • 外部函數(shù)被調(diào)用后,返回內(nèi)部函數(shù),導(dǎo)致內(nèi)部函數(shù)被外界變量 c 引用。

  • JavaScript 解析器檢測到外部函數(shù)的活動(dòng)對(duì)象的屬性被外界引用,無法注銷該活動(dòng)對(duì)象,于是在內(nèi)存中繼續(xù)維持該對(duì)象的存在。

  • 當(dāng)調(diào)用 c,即調(diào)用內(nèi)部函數(shù)時(shí),可以看到外部函數(shù)的參數(shù) x 存儲(chǔ)的值繼續(xù)存在。這樣就可以實(shí)現(xiàn)后續(xù)運(yùn)算操作,返回 x+y=5=6=11。

如下結(jié)構(gòu)形式也可以形成閉包:通過全局變量引用內(nèi)部函數(shù),實(shí)現(xiàn)內(nèi)部函數(shù)對(duì)外開放。

var c;  //聲明全局變量 function f(x) {  //外部函數(shù)     c = function (y) {  //內(nèi)部函數(shù),通過向全局變量開放實(shí)現(xiàn)外部引用         return x + y;  //訪問外部函數(shù)的參數(shù)     }; } f(5);  //調(diào)用外部函數(shù) console.log(c(6));  //使用全局變量c調(diào)用內(nèi)部函數(shù),返回11

閉包變體

除了嵌套函數(shù)外,如果外部引用函數(shù)內(nèi)部的私有數(shù)組或?qū)ο螅踩菀仔纬砷]包。

var add;  //全局變量 function f() {  //外部函數(shù)     var a = [1,2,3];  //私有變量,引用型數(shù)組     add = function (x) {  //測試函數(shù),對(duì)外開放         a[0] = x * x;  //修改私有數(shù)組的元素值     }     return a;  //返回私有數(shù)組的引用 } var c = f(); console.log(c[0]);  //讀取閉包內(nèi)數(shù)組,返回1 add(5);  //測試修改數(shù)組 console.log(c[0]);  //讀取閉包內(nèi)數(shù)組,返回25 add(10);  //測試修改數(shù)組 console.log(c[0]);  //讀取閉包內(nèi)數(shù)組,返回100

與函數(shù)相同,對(duì)象和數(shù)組也是引用型數(shù)據(jù)。調(diào)用函數(shù) f,返回私有數(shù)組 a 的引用,即傳值給局部變量 c,而 a 是函數(shù) f 的私有變量,當(dāng)被調(diào)用后,活動(dòng)對(duì)象繼續(xù)存在,這樣就形成了閉包。

這種特殊形式的閉包沒有實(shí)際應(yīng)用價(jià)值,因?yàn)槠涔δ軉我唬荒茏鳛橐粋€(gè)靜態(tài)的、單向的閉包。而閉包函數(shù)可以設(shè)計(jì)各種復(fù)雜的運(yùn)算表達(dá)式,它是函數(shù)式變成的基礎(chǔ)。

反之,如果返回的是一個(gè)簡單的值,就無法形成閉包,值傳遞是直接復(fù)制。外部變量 c 得到的僅是一個(gè)值,而不是對(duì)函數(shù)內(nèi)部變量的引用。這樣當(dāng)函數(shù)調(diào)用后,將直接注銷對(duì)象。

function f(x) {  //外部函數(shù)     var a = 1;  //私有變量     return a; } var c = f(5); console.log(c);  //僅是一個(gè)值,返回1

使用閉包

下面結(jié)合示例介紹閉包的簡單使用,以加深對(duì)閉包的理解。

示例1

使用閉包實(shí)現(xiàn)優(yōu)雅的打包,定義存儲(chǔ)器。

var f = function () {  //外部函數(shù)     var a = [];  //私有數(shù)組初始化     return function (x) {  //返回內(nèi)部函數(shù)         a.push(x);  //添加元素         return a;  //返回私有數(shù)組     }; } ()  //直接調(diào)用函數(shù),生成執(zhí)行環(huán)境 var a = f(1);  //添加值 console.log(a);  //返回1 var b = f(2);  //添加值 console.log(b);  //返回1,2

在上面示例中,通過外部函數(shù)設(shè)計(jì)一個(gè)閉包,定義一個(gè)永久的存儲(chǔ)器。當(dāng)調(diào)用外部函數(shù)生成執(zhí)行環(huán)境之后,就可以利用返回的匿名函數(shù)不斷地的向閉包體內(nèi)的數(shù)組 a 傳入新值,傳入的值會(huì)持續(xù)存在。

示例2

在網(wǎng)頁中事件處理函數(shù)很容易形成閉包。

<script> function f() {     var a = 1;     b = function () {         console.log("a =" + a);     }     c = function () {         a ++;     }     d = function () {         a --;     } } </script> <button onclick="f()">生成閉包</button> <button onclick="b()">查看 a 的值</button> <button onclick="c()">遞增</button> <button onclick="d()">遞減</button>

在瀏覽器中瀏覽時(shí),首先點(diǎn)擊“生成閉包”按鈕,生成一個(gè)閉包;點(diǎn)擊“查看 a 的值”按鈕,可以隨時(shí)查看閉包內(nèi)私有變量 a 的值;點(diǎn)擊“遞增”“遞減”按鈕時(shí),可以動(dòng)態(tài)修改閉包內(nèi)變量 a 的值,效果如圖所示。

javascript閉包是作用域嗎

閉包的局限性

閉包的價(jià)值是方便在表達(dá)式運(yùn)算過程中存儲(chǔ)數(shù)據(jù)。但是,它的缺點(diǎn)也不容忽視。

  • 由于函數(shù)調(diào)用后,無法注銷調(diào)用對(duì)象,會(huì)占用系統(tǒng)資源,在腳本中大量使用閉包,容易導(dǎo)致內(nèi)存泄漏。解決方法:慎用閉包,不要濫用。

  • 由于閉包的作用,其保存的值是動(dòng)態(tài),如果處理不當(dāng)容易出現(xiàn)異常或錯(cuò)誤。

示例

設(shè)計(jì)一個(gè)簡單的選項(xiàng)卡效果。HTML 結(jié)構(gòu)如下:

<div class="tab_wrap">     <ul class="tab" id="tab">         <li id="tab_1" class="hover">Tab1</li>         <li id="tab_2" class="normal">Tab2</li>         <li id="tab_3" class="normal">Tab3</li>     </ul>     <div class="content" id="content">         <div id="content_1" class="show"><img scr="image/1.jpg" height="200" /></div>         <div id="content_2" class="show"><img scr="image/2.jpg" height="200" /></div>         <div id="content_3" class="show"><img scr="image/3.jpg" height="200" /></div>     </div> </div>

下面請(qǐng)看 JavaScript 腳本。

window.onload = function () {     var tab = document.getElementById("tab").getElementsByTagName("li"),         content = document.getElementById("content").getElementByTagName("div");     for (var i = 0; i < tab.length;i ++) {         tab[i].addEventListener("mouseover"), function () {             for (var n = 0; n < tab.length; n ++) {                 tab[n].className = "normal";                 content[n].className = "none";             }             tab[i].className = "hover";             content[i].className = "show";         });     } }

在 load 事件處理函數(shù)中,使用 for 語句為每個(gè) li 屬性元素綁定 mouseover 事件;在 mouseover 事件處理函數(shù)中重置所有選項(xiàng)卡 li 的類樣式,然后設(shè)置當(dāng)前 li 選項(xiàng)卡高亮顯示,同時(shí)顯示對(duì)應(yīng)的內(nèi)容容器。

但是在瀏覽器中預(yù)覽時(shí),會(huì)發(fā)現(xiàn)瀏覽器拋出異常。

SCRIPT5007:無法設(shè)置未定義或 null 引用的屬性"className"

在 mouseover 事件處理函數(shù)中跟蹤變量 i 的值,i 的值都變?yōu)榱?3,tab[3] 自然是一個(gè) null,所以也不能夠讀取 className 屬性。

【原因分析】

上面 JavaScript 代碼是一個(gè)典型的嵌套函數(shù)結(jié)構(gòu)。外部函數(shù)為 load 事件處理函數(shù),內(nèi)部函數(shù)為 mouseover 事件處理函數(shù),變量 i 為外部函數(shù)的私有變量。

通過事件綁定,mouseover 事件處理函數(shù)被外界引用(li 元素),這樣就形成了一個(gè)閉包體。雖然在 for 語句中為每個(gè)選項(xiàng)卡 li 分別綁定事件處理函數(shù),但是這個(gè)操作是動(dòng)態(tài)的,因此 tab[i] 中 i 的值也是動(dòng)態(tài)的,所以就出現(xiàn)了上述異常。

【解決方法】

解決閉包的缺陷,最簡單的方法是阻斷內(nèi)部函數(shù)對(duì)外部函數(shù)的變量引用,這樣就形成了閉包體。針對(duì)本示例,我們可以在內(nèi)部函數(shù)(mouseover 事件處理函數(shù))外邊增加一層防火墻,不讓其直接引用外部變量。

window.load = function () {     var tab = document.getElementById("tab").getElementsByTagName("li"),         content = document.getElementById("content").getElementsByTagName("div");     for (var i = 0; i < tab.length; i ++ ) {         (function (j) {             tab[j].addEventListener("number", function () {                 for (var n = 0; n < tab.length; n ++) {                     tab[n].className = "normal";                     content[n].className = "none";                 }                 tab[j].className = "hover";                 conteng[j].className = "show";             });         }) (i);     } }

在 for 語句中,直接調(diào)用匿名函數(shù),把外部函數(shù)的 i 變量傳給調(diào)用函數(shù),在調(diào)用函數(shù)中接收這個(gè)值,而不是引用外部變量 i,規(guī)避了閉包體帶來的困惑。

【推薦學(xué)習(xí):javascript高級(jí)教程】

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
熟妇与小伙子MATUR老熟妇E| 啪啪无码人妻丰满熟妇| 女女女女女裸体处开BBB| 欧美成人一区二区三区在线观看| 人妻AV中文字幕一区二区三区| 色综合视频一区二区三区44 | 高清国产天干天干天干不卡顿| 高清国产天干天干天干| 好男人官网在线观看免费播放| 久久久久精品国产亚洲AV蜜桃| 女警察受呻吟双腿大开H| 日本丰满熟妇多毛| 无翼乌工口肉肉无遮挡无码18| 亚洲精品无码AV人在线观看| 中文字幕人妻不在线无码视频 | 在线观看中文最近最新观看| 草莓视频在线播放视频| 国产精品国产三级国产AV′| 性丰满ⅩXXOOO性HD| 亚洲另类激情综合偷自拍图| 中文字幕日本六区小电影| 把女人弄爽特黄A大片片| 国产女人水真多18毛片18精品| 久久久久黑人强伦姧人妻| 女人脱精光直播APP下载| 十八禁午夜私人在线观看影院| 亚洲国产无套无码AV电影| 18禁无遮挡无码网站免费| 父母儿女一家换着玩的文案| 精品黑人一区二区三区| 国产在线蜜乳一区二区三区| 久久天天躁夜夜躁狠狠躁2022| 日本19禁啪啪吃奶大尺度| 亚洲AV高清在线一区二区三区| 亚洲AV成人无码久久精品| 影音先锋女人AV女色资源| 一出一进一爽一粗一大视频免费的| WWW射我里面在线观看| 国产亚洲精品无码不卡| 男男GAY腐片GⅤ2022| 玩弄丰满熟妇乱XXXXX性多毛 | 国产成人无码精品久久久小说 | 被老头侵犯的人妻| 成人毛片18女人毛片免费视频末| 黑人巨大精品人妻一区二区| 女人浓毛巨茎ⅩXXOOO| 亚洲 日韩 另类 制服 无码| 99精品热6080YY久久| WW久久综合久中文字幕| 果冻传媒影视在线播放| 人妻AⅤ中文字幕| 亚洲国产成人五月综合网| YSL水蜜桃86| 精品久久久久久无码人妻VR| 日韩精品卡2卡3卡4卡5| 一本大道一卡2卡三卡4卡国产| 公天天吃我奶躁我的在线观看| 国产沙发午睡系列999| 嫩小槡BBBB槡BBBB槡| 亚洲AV无码专区日韩乱码不卡| STEAMWORKSHOP魅魔| 精品久久久BBBB人妻| 少妇的BBW性大片| 性饥渴的少妇AV无码影片| 2022色婷婷综合久久久| 韩国无码无遮挡在线观看不卡| 人妻中出受孕 中文字幕在线| 亚洲中文字幕精品无码AV| 国产成人AV一区二区三区无码 | 国产成人AⅤ片在线观看| 女人被弄高潮视频免费| 亚洲精品卡一卡2卡3卡4卡| 丰满少妇高潮惨叫在线观看| 内射猛交XXXXⅩX最新消息| 亚洲国产精品无码久久一区二区| 高潮颤抖大叫正在线播放| 女人浓毛巨茎ⅩXXOOO| 亚洲午夜国产成人AV电影| 99精品久久精品一区二区| 精品国产AⅤ一区二区三区在线看| 少妇无码人妻一区二区三区| AⅤ日本亚洲欧洲免费| 久久欧美极品少妇XXXXⅩ| 亚洲AAAAA特级| 丰满岳跪趴高撅肥臀| 欧美一级 片内射黑人B| 野兽的夜晚第四季忘不掉的前任 | 成人特黄A级毛片免费视频| 蜜臀av一区二区蜜臀AV免费| 三上悠亚AV资源站| 67194熟妇人妻欧美日韩| 久久精品国产72国产精| 亚洲AV蜜乳永久www| 国产V亚洲V天堂A无码| 人物动物交互第LL0集| 99精品国产福久久久久久蜜桃| 久久精品饰品有限公司网站| 亚洲AV秘 无码一区二区三密桃 | 亚洲А∨天堂男人色无码| 国产精品边做奶水狂喷无码| 揉大N呻吟水多大棒子| 扒开双腿猛进入喷水高潮叫声| 蜜臀AV午夜一区二区三区 | 二人世界免费观看正片在线观看| 精品久久久久久国产| 性BBBBBB裸体BBBBB开| 国产丰满美女A级毛片| 日韩无人区码卡二卡3卡一| WWW.嫩草AV天堂影院| 男女性杂交内射妇女BBWXZ| 尤物爽到高潮潮喷视频大全| 久久久久国色AV免费观看性色| 亚洲精品国产AV现线| 狠狠色噜噜狠狠狠7777奇米| 亚洲AV无码日韩精品影片| 巴西女人与禽2O2O性论交| 欧美极度另类XXⅩOO| 97AV麻豆蜜桃一区二区| 免费无码黄动漫在线观看| 中文字幕久久波多野结衣AV不卡 | www.黄色AV考逼| 欧洲免费无码视频在线| らだ天堂中文在线| 久久精品熟女亚洲AV麻豆网站| 亚洲欧美成人精品香蕉网| 久久99国产精品久久99| 天堂国品一二三产品区别大吗| 高一数学网课免费-2| 少女たちよ在线观看动漫4集免费| 成人无码视频97免费| 少妇高潮喷水在线观看| 国产成人久久久精品二区三区 | 色欲香天天天综合网站小说| 国产AV人人夜夜澡人人爽小说| 图片 小说 校园 激情 都市| 国产精品人人妻人色五月| 亚洲AV无码精品色午夜蛋壳 | 国产精品日本一区二区不卡视频 | 92久久偷偷做嫩草影院免费看| 欧美乱妇日本无乱码特黄大片| 八戒八戒WWW资源高清| 日日碰狠狠添天天爽无码| 国产粉嫩嫩00在线正在播放| 亚洲AV色一区二区三区蜜桃 | 忘忧草WWW中文在线资源| 国产亚洲AV片在线观看播放按摩 | 国产精品成人一区二区三区| 亚洲AV成人无码网站| 久久99久久99精品免观看| 制服 丝袜 人妻 专区一本| 欧美日韩人妻精品一区在线| 夜鲁鲁鲁夜夜综合视频欧美| 免费人成在线观看网站品善网 | 久久久久久亚洲AV成人无码国产| 在办公室伦流澡到高潮H| 欧美亚洲日韩AⅤ在线观看| 高中女无套中出17P| 亚洲AV成人片无码网站网一区 | 一边做一边喷17P| 人妻丰满AV中文久久不卡| 国产精品99久久久久久人| 亚洲精品国产美女久久久99| 蜜桃AV无码国产丝袜在线观看 | 欧美黑人猛XXxXX内射| 高H禁伦餐桌上的肉伦NP| 亚洲AV狠狠爱一区二区三区| 老熟妇毛茸茸BBW视频| 宝贝别忍着喷出来| 无码人妻久久一区二区三区不卡 | 1—36集电视剧免费观看36集| 日本老熟妇毛茸茸| 国产日韩一区二区三区在线观看| 亚洲中文字幕无码AV| 人妻丰满熟妇av无码区HD优| 国产看黄网站又黄又爽又色| 一边摸一边抽搐一进一出视频| 人妻无码一区二区三区| 国产色无码精品视频免费| 泑女网址WWW呦女| 日韩乱码人妻无码中文视频| 狠狠色欧美亚洲综合色| 99成人国产综合久久精品| 忘忧草在线社区日本WWW| 久久蜜桃86人妻arvi| 成人免费无码大片A毛片直播| 亚洲AV高清在线一区二区三区| 末成年女A∨片一区二区| 国产成人无码A区在线| 一本一道久久A久久精品综合| 日韩精品无码一区二区三区| 精品国产一区AV天美传媒| PORNO日本╳╳╳| 亚洲AV永久无码精品秋霞电影影院| 能让我流水水的一千字| 国产美女丝袜一级肛交蜜桃| 337P日本欧洲亚洲大胆| 午夜亚洲国产理论片亚洲2020| 女人和拘做受全过程免费| 国产尤物AV尤物在线观看| JAVASCRIPTJAVA成熟亲子|