av激情亚洲男人的天堂国语,日韩欧美精品一中文字幕,无码av一区二区三区无码,国产又色又爽又刺激的a片,国产又色又爽又刺激的a片

前端百題斬——用“閉包”問題征服面試官

13.1 定義

在JavaScript中,根據(jù)詞法作用域的規(guī)則,內部函數(shù)總是可以訪問其外部函數(shù)聲明的變量,當通過調用一個外部函數(shù)返回一個內部函數(shù)后,即使該外部函數(shù)已經(jīng)執(zhí)行結束了,但是內部函數(shù)引用外部函數(shù)的變量依然保存在內存中,就把這些變量的集合稱為閉包。

13.2 閉包實現(xiàn)

在一個函數(shù)中嵌套另一個函數(shù)或者將一個匿名函數(shù)作為值傳入另一個函數(shù)中。

 
 
 
 
  1. // 函數(shù)fun1中嵌套了fun2,fun2作為參數(shù)返回,外部調用時仍能打印val1,構成閉包 
  2. function fun1() { 
  3.     const val1 = 10; 
  4.     function fun2() { 
  5.         console.log(val1); 
  6.     } 
  7.  
  8.     return fun2; 
  9.  
  10. function fun3() { 
  11.     const val2 = 20; 
  12.     // 定時器中的為一個匿名函數(shù),其作為參數(shù)傳入了,函數(shù)fun3執(zhí)行完畢之后,1s鐘后才會執(zhí)行定時器函數(shù),但此時還能打印val2,構成閉包 
  13.     setTimeout(function() { 
  14.         console.log(val2); 
  15.     }, 1000); 

13.3 流程

根據(jù)下面的函數(shù)來看看閉包的整個執(zhí)行流程

 
 
 
 
  1. function main() { 
  2.     const val1 = 20; 
  3.     var val2 = 2 
  4.     function valResult() { 
  5.         return val1 * val2; 
  6.     } 
  7.  
  8.     return valResult; 
  9.  
  10. var result = main(); 
  11. console.log(result()); // 40 

上圖中展示了各個時期的調用棧,需要重點關注以下幾點:

  1. 當main函數(shù)執(zhí)行完畢后,main函數(shù)的執(zhí)行上下文從棧頂彈出;
  2. 返回的方法(valResult)中調用了main函數(shù)中的val1和val2變量,這兩個變量就會打包成closure閉包,加到[[scopes]];
  3. 調用返回的方法時,作用域鏈為:result函數(shù)作用域——Closure(main)——全局作用域

13.4 優(yōu)缺點

優(yōu)點

(1)可以重復使用變量,并且不會造成變量污染;

(2)可以用來定義私有屬性和私有方法

缺點

(1)會產生不銷毀的上下文,導致棧/堆內存消耗過大

(2)會造成內存泄露。

擴展:閉包是怎么回收的?

  1. 如果閉包引入的函數(shù)是一個全局變量,那么閉包會一直存在直到頁面關閉;但如果這個閉包以后不再使用的話,就會造成內存泄露;
  2. 如果引用閉包的函數(shù)是一個局部變量,等函數(shù)銷毀后,在下次JavaScript引擎執(zhí)行垃圾回收時,判斷閉包內容已經(jīng)不再被使用,則js引擎的垃圾回收器就會進行回收。

13.5 用途

閉包用途主要有以下兩個:

創(chuàng)建私有變量

 
 
 
 
  1. function MyName(name) { 
  2.     return { 
  3.         getName() { 
  4.             return name; 
  5.         } 
  6.     } 
  7.  
  8. const myName = MyName('lili'); 
  9. // 只能通過getName訪問對應的名字,別的方式訪問不到 
  10. console.log(myName.getName()); // lili 

作為回調函數(shù)。當把函數(shù)作為值傳遞到某處,并在某個時刻進行回調的時候就會創(chuàng)建一個閉包。例如定時器、DOM事件監(jiān)聽器、Ajax請求。

 
 
 
 
  1. function fun(name) { 
  2.     setTimeout(() => { 
  3.         console.log(name); 
  4.     }, 1000); 
  5.  
  6. fun('linlin'); 

13.6 經(jīng)典閉包問題

多個子函數(shù)的[[scope]]都是同時指向父級,是完全共享的。因此當父級的變量對象被修改時,所有子函數(shù)都受到影響。

 
 
 
 
  1. for (var i = 1; i < 5; i++) { 
  2.     setTimeout(() => console.log(i), 1000); 

上述代碼本意是輸出1、2、3、4,但結果卻是四個5,為了解決該問題,主要有三種辦法。

變量可以通過 函數(shù)參數(shù)的形式 傳入,避免使用默認的[[scope]]向上查找

 
 
 
 
  1. for (var i = 1; i < 5; i++) { 
  2.     (function(i) { 
  3.         setTimeout(() => console.log(i), 1000); 
  4.     })(i); 

使用setTimeout包裹,通過第三個參數(shù)傳入。(注:setTimeout后面可以有多個參數(shù),從第三個參數(shù)開始其就作為回掉函數(shù)的附加參數(shù))

 
 
 
 
  1. for (var i = 1; i < 5; i++) { 
  2.     setTimeout(value => console.log(value), 1000, i); 

使用 塊級作用域,讓變量成為自己上下文的屬性,避免共享

 
 
 
 
  1. for (let i = 1; i < 5; i++) { 
  2.     setTimeout(() => console.log(i), 1000); 

本文轉載自微信公眾號「執(zhí)鳶者」,可以通過以下二維碼關注。轉載本文請聯(lián)系執(zhí)鳶者公眾號。


文章名稱:前端百題斬——用“閉包”問題征服面試官
當前URL:http://uogjgqi.cn/article/dheocsp.html
掃二維碼與項目經(jīng)理溝通

我們在微信上24小時期待你的聲音

解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網(wǎng)交流