成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

[[403566]]

13.1 定義

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

13.2 閉包實現

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

  1. // 函數fun1中嵌套了fun2,fun2作為參數返回,外部調用時仍能打印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.     // 定時器中的為一個匿名函數,其作為參數傳入了,函數fun3執行完畢之后,1s鐘后才會執行定時器函數,但此時還能打印val2,構成閉包 
  13.     setTimeout(function() { 
  14.         console.log(val2); 
  15.     }, 1000); 

13.3 流程

根據下面的函數來看看閉包的整個執行流程

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

13.4 優缺點

優點

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

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

缺點

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

(2)會造成內存泄露。

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

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

13.5 用途

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

創建私有變量

  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 

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

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

13.6 經典閉包問題

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

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

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

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

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

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

  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); 

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

 

責任編輯:武曉燕 來源: 執鳶者
相關推薦

2019-07-09 10:43:57

JavaScriptWeb前端

2025-03-18 12:00:00

閉包JavaScript前端

2021-10-19 22:23:05

typeof方式Instanceof

2021-05-09 22:00:59

TypeofInstanceof運算符

2024-08-08 16:53:17

2018-04-13 14:53:13

PythonMySQL爬蟲

2021-05-30 19:02:59

變量對象上下文

2021-06-09 07:01:30

前端CallApply

2021-07-14 07:00:53

瀏覽器技巧前端

2021-10-18 09:01:01

前端賦值淺拷貝

2021-08-04 06:56:49

HTTP緩存前端

2021-05-12 07:04:55

Js變量方式

2021-11-19 09:01:09

防抖節流前端

2021-07-26 05:01:55

瀏覽器渲染流程

2021-06-28 07:12:28

賦值淺拷貝深拷貝

2021-04-13 19:05:06

Go閉包面試

2021-05-19 07:02:42

JS對象方法

2021-05-16 19:23:11

引用類型包裝

2021-06-07 07:01:43

js關鍵字運行

2021-06-11 06:54:34

原型構造函數
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品一区二区在线播放 | 四虎在线视频 | 伊人伊成久久人综合网站 | 色综合色综合色综合 | 国产精品久久久久av | 国产精品日日夜夜 | 91豆花视频 | 在线成人免费视频 | 国产美女在线播放 | 亚洲精久久 | 国产日韩欧美一区二区在线播放 | 精品亚洲国产成av人片传媒 | 正在播放国产精品 | 不卡在线视频 | 国产在线中文字幕 | 中文字幕欧美一区 | 精品国产一区一区二区三亚瑟 | 天天干天天爽 | 天天干天天草 | 91欧美精品成人综合在线观看 | 黄在线免费观看 | 欧美在线视频观看 | 欧洲一区在线观看 | 精品欧美一区免费观看α√ | 久久九| 91免费版在线观看 | 亚洲一区二区三区在线视频 | 69视频在线播放 | 精品成人一区二区 | 日韩视频91| 亚洲欧美视频一区 | 精品一区在线免费观看 | 国产精品一区二区福利视频 | 免费国产视频 | 欧美一区二区黄 | 成人免费大片黄在线播放 | 先锋av资源网 | 免费久久网站 | 欧美精品在线一区二区三区 | 狠狠狠| 国产区在线免费观看 |