掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網(wǎng)交流
在JavaScript中,根據(jù)詞法作用域的規(guī)則,內部函數(shù)總是可以訪問其外部函數(shù)聲明的變量,當通過調用一個外部函數(shù)返回一個內部函數(shù)后,即使該外部函數(shù)已經(jīng)執(zhí)行結束了,但是內部函數(shù)引用外部函數(shù)的變量依然保存在內存中,就把這些變量的集合稱為閉包。

在一個函數(shù)中嵌套另一個函數(shù)或者將一個匿名函數(shù)作為值傳入另一個函數(shù)中。
- // 函數(shù)fun1中嵌套了fun2,fun2作為參數(shù)返回,外部調用時仍能打印val1,構成閉包
- function fun1() {
- const val1 = 10;
- function fun2() {
- console.log(val1);
- }
- return fun2;
- }
- function fun3() {
- const val2 = 20;
- // 定時器中的為一個匿名函數(shù),其作為參數(shù)傳入了,函數(shù)fun3執(zhí)行完畢之后,1s鐘后才會執(zhí)行定時器函數(shù),但此時還能打印val2,構成閉包
- setTimeout(function() {
- console.log(val2);
- }, 1000);
- }
根據(jù)下面的函數(shù)來看看閉包的整個執(zhí)行流程
- function main() {
- const val1 = 20;
- var val2 = 2
- function valResult() {
- return val1 * val2;
- }
- return valResult;
- }
- var result = main();
- console.log(result()); // 40
上圖中展示了各個時期的調用棧,需要重點關注以下幾點:
優(yōu)點
(1)可以重復使用變量,并且不會造成變量污染;
(2)可以用來定義私有屬性和私有方法
缺點
(1)會產生不銷毀的上下文,導致棧/堆內存消耗過大
(2)會造成內存泄露。
擴展:閉包是怎么回收的?
閉包用途主要有以下兩個:
創(chuàng)建私有變量
- function MyName(name) {
- return {
- getName() {
- return name;
- }
- }
- }
- const myName = MyName('lili');
- // 只能通過getName訪問對應的名字,別的方式訪問不到
- console.log(myName.getName()); // lili
作為回調函數(shù)。當把函數(shù)作為值傳遞到某處,并在某個時刻進行回調的時候就會創(chuàng)建一個閉包。例如定時器、DOM事件監(jiān)聽器、Ajax請求。
- function fun(name) {
- setTimeout(() => {
- console.log(name);
- }, 1000);
- }
- fun('linlin');
多個子函數(shù)的[[scope]]都是同時指向父級,是完全共享的。因此當父級的變量對象被修改時,所有子函數(shù)都受到影響。
- for (var i = 1; i < 5; i++) {
- setTimeout(() => console.log(i), 1000);
- }
上述代碼本意是輸出1、2、3、4,但結果卻是四個5,為了解決該問題,主要有三種辦法。
變量可以通過 函數(shù)參數(shù)的形式 傳入,避免使用默認的[[scope]]向上查找
- for (var i = 1; i < 5; i++) {
- (function(i) {
- setTimeout(() => console.log(i), 1000);
- })(i);
- }
使用setTimeout包裹,通過第三個參數(shù)傳入。(注:setTimeout后面可以有多個參數(shù),從第三個參數(shù)開始其就作為回掉函數(shù)的附加參數(shù))
- for (var i = 1; i < 5; i++) {
- setTimeout(value => console.log(value), 1000, i);
- }
使用 塊級作用域,讓變量成為自己上下文的屬性,避免共享
- for (let i = 1; i < 5; i++) {
- setTimeout(() => console.log(i), 1000);
- }
本文轉載自微信公眾號「執(zhí)鳶者」,可以通過以下二維碼關注。轉載本文請聯(lián)系執(zhí)鳶者公眾號。

我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網(wǎng)交流