您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“JavaScript中“閉包”的含義和作用”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“JavaScript中“閉包”的含義和作用”吧!
在JavaScript中,根據(jù)詞法作用域的規(guī)則,內(nèi)部函數(shù)總是可以訪(fǎng)問(wèn)其外部函數(shù)聲明的變量,當(dāng)通過(guò)調(diào)用一個(gè)外部函數(shù)返回一個(gè)內(nèi)部函數(shù)后,即使該外部函數(shù)已經(jīng)執(zhí)行結(jié)束了,但是內(nèi)部函數(shù)引用外部函數(shù)的變量依然保存在內(nèi)存中,就把這些變量的集合稱(chēng)為閉包。
在一個(gè)函數(shù)中嵌套另一個(gè)函數(shù)或者將一個(gè)匿名函數(shù)作為值傳入另一個(gè)函數(shù)中。
// 函數(shù)fun1中嵌套了fun2,fun2作為參數(shù)返回,外部調(diào)用時(shí)仍能打印val1,構(gòu)成閉包 function fun1() { const val1 = 10; function fun2() { console.log(val1); } return fun2; } function fun3() { const val2 = 20; // 定時(shí)器中的為一個(gè)匿名函數(shù),其作為參數(shù)傳入了,函數(shù)fun3執(zhí)行完畢之后,1s鐘后才會(huì)執(zhí)行定時(shí)器函數(shù),但此時(shí)還能打印val2,構(gòu)成閉包 setTimeout(function() { console.log(val2); }, 1000); }
根據(jù)下面的函數(shù)來(lái)看看閉包的整個(gè)執(zhí)行流程
function main() { const val1 = 20; var val2 = 2 function valResult() { return val1 * val2; } return valResult; } var result = main(); console.log(result()); // 40
上圖中展示了各個(gè)時(shí)期的調(diào)用棧,需要重點(diǎn)關(guān)注以下幾點(diǎn):
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
當(dāng)main函數(shù)執(zhí)行完畢后,main函數(shù)的執(zhí)行上下文從棧頂彈出;
返回的方法(valResult)中調(diào)用了main函數(shù)中的val1和val2變量,這兩個(gè)變量就會(huì)打包成closure閉包,加到[[scopes]];
調(diào)用返回的方法時(shí),作用域鏈為:result函數(shù)作用域——Closure(main)——全局作用域
優(yōu)點(diǎn)
(1)可以重復(fù)使用變量,并且不會(huì)造成變量污染;
(2)可以用來(lái)定義私有屬性和私有方法
缺點(diǎn)
(1)會(huì)產(chǎn)生不銷(xiāo)毀的上下文,導(dǎo)致棧/堆內(nèi)存消耗過(guò)大
(2)會(huì)造成內(nèi)存泄露。
擴(kuò)展:閉包是怎么回收的?
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
如果閉包引入的函數(shù)是一個(gè)全局變量,那么閉包會(huì)一直存在直到頁(yè)面關(guān)閉;但如果這個(gè)閉包以后不再使用的話(huà),就會(huì)造成內(nèi)存泄露;
如果引用閉包的函數(shù)是一個(gè)局部變量,等函數(shù)銷(xiāo)毀后,在下次JavaScript引擎執(zhí)行垃圾回收時(shí),判斷閉包內(nèi)容已經(jīng)不再被使用,則js引擎的垃圾回收器就會(huì)進(jìn)行回收。
閉包用途主要有以下兩個(gè):
創(chuàng)建私有變量
function MyName(name) { return { getName() { return name; } } } const myName = MyName('lili'); // 只能通過(guò)getName訪(fǎng)問(wèn)對(duì)應(yīng)的名字,別的方式訪(fǎng)問(wèn)不到 console.log(myName.getName()); // lili
作為回調(diào)函數(shù)。當(dāng)把函數(shù)作為值傳遞到某處,并在某個(gè)時(shí)刻進(jìn)行回調(diào)的時(shí)候就會(huì)創(chuàng)建一個(gè)閉包。例如定時(shí)器、DOM事件監(jiān)聽(tīng)器、Ajax請(qǐng)求。
function fun(name) { setTimeout(() => { console.log(name); }, 1000); } fun('linlin');
多個(gè)子函數(shù)的[[scope]]都是同時(shí)指向父級(jí),是完全共享的。因此當(dāng)父級(jí)的變量對(duì)象被修改時(shí),所有子函數(shù)都受到影響。
for (var i = 1; i < 5; i++) { setTimeout(() => console.log(i), 1000); }
上述代碼本意是輸出1、2、3、4,但結(jié)果卻是四個(gè)5,為了解決該問(wèn)題,主要有三種辦法。
變量可以通過(guò) 函數(shù)參數(shù)的形式 傳入,避免使用默認(rèn)的[[scope]]向上查找
for (var i = 1; i < 5; i++) { (function(i) { setTimeout(() => console.log(i), 1000); })(i); }
使用setTimeout包裹,通過(guò)第三個(gè)參數(shù)傳入。(注:setTimeout后面可以有多個(gè)參數(shù),從第三個(gè)參數(shù)開(kāi)始其就作為回掉函數(shù)的附加參數(shù))
for (var i = 1; i < 5; i++) { setTimeout(value => console.log(value), 1000, i); }
使用 塊級(jí)作用域,讓變量成為自己上下文的屬性,避免共享
for (let i = 1; i < 5; i++) { setTimeout(() => console.log(i), 1000); }
到此,相信大家對(duì)“JavaScript中“閉包”的含義和作用”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。