面試官問我:什么是JavaScript閉包,我該如何回答


閉包,有人說它是一種設計理念,有人說所有的函數都是閉包。到底什么是閉包?這個問題在面試是時候經常都會被問,很多小白一聽就懵逼了,不知道如何回答好。

這個問題也有很多朋友在公眾號給李老師留言了,問題表達方式不一樣,都是終歸到一點,就是對閉包沒有很清晰的理解。大家經常去網上找相關資料,但是對閉包的說法都是各種各樣的,讓大家對閉包的定義沒有一個概念。
更多網頁前端開發教程,行業資訊,面試技巧,歡迎關注前端開發學習公眾號:網頁前端開發學習

今天我們就來一起講講什么是閉包,幫助大家理解,今天的內容可以直接收藏起來。方便以后看。

什么是閉包(Closure)

簡單講,閉包就是指有權訪問另一個函數作用域中的變量的函數。
MDN 上面這么說:閉包是一種特殊的對象。
它由兩部分構成:函數,以及創建該函數的環境。環境由閉包創建時在作用域中的任何局部變量組成。

這種官方的概念是比較難理解的,在面試的時候說出來也不是很專業,因為沒辦法有個具體的邏輯。
我個人認為,理解閉包的關鍵在于:外部函數調用之后其變量對象本應該被銷毀,但閉包的存在使我們仍然可以訪問外部函數的變量對象,這就是閉包的重要概念。


產生一個閉包

創建閉包最常見方式,就是在一個函數內部創建另一個函數。下面例子中的 closure 就是一個閉包:
閉包的作用域鏈包含著它自己的作用域,以及包含它的函數的作用域和全局作用域。

閉包的注意事項

.通常,函數的作用域及其所有變量都會在函數執行結束后被銷毀。但是,在創建了一個閉包以后,這個函數的作用域就會一直保存到閉包不存在為止。
從上述代碼可以看到add5 和 add10 都是閉包。它們共享相同的函數定義,但是保存了不同的環境。在 add5 的環境中,x 為 5。而在 add10 中,x 則為 10。最后通過 null 釋放了 add5 和 add10 對閉包的引用。
在javascript中,如果一個對象不再被引用,那么這個對象就會被垃圾回收機制回收;
如果兩個對象互相引用,而不再被第3者所引用,那么這兩個互相引用的對象也會被回收。

閉包只能取得包含函數中任何變量的最后一個值

大家看一下上面這個代碼,arr數組中包含了10個匿名函數,每個匿名函數都能訪問外部函數的變量i,那么i是多少呢?
當arrFunc執行完畢后,其作用域被銷毀,但它的變量對象仍保存在內存中,得以被匿名訪問,這時i的值為10。
要想保存在循環過程中每一個i的值,需要在匿名函數外部再套用一個匿名函數,在這個匿名函數中定義另一個變量并且立即執行來保存i的值。
這時最內部的匿名函數訪問的是num的值,所以數組中10個匿名函數的返回值就是1-10。

閉包中的this對象

在上面這段代碼中,obj.getName()()實際上是在全局作用域中調用了匿名函數,this指向了window。
這里要理解函數名與函數功能是分割開的,不要認為函數在哪里,其內部的this就指向哪里。
window才是匿名函數功能執行的環境。
如果想使this指向外部函數的執行環境,可以這樣改寫:
在閉包中,arguments與this也有相同的問題。下面的情況也要注意:
obj.getName();這時getName()是在對象obj的環境中執行的,所以this指向obj。
(obj.getName = obj.getName)賦值語句返回的是等號右邊的值,在全局作用域中返回,所以(obj.getName = obj.getName)();的this指向全局。要把函數名和函數功能分割開來。

內存泄漏

閉包會引用包含函數的整個變量對象,如果閉包的作用域鏈中保存著一個HTML元素,那么就意味著該元素無法被銷毀。所以我們有必要在對這個元素操作完之后主動銷毀。

函數內部的定時器

當函數內部的定時器引用了外部函數的變量對象時,該變量對象不會被銷毀。

閉包的應用

應用閉包的主要場合是:設計私有的方法和變量。
任何在函數中定義的變量,都可以認為是私有變量,因為不能在函數外部訪問這些變量。私有變量包括函數的參數、局部變量和函數內定義的其他函數。
把有權訪問私有變量的公有方法稱為特權方法(privileged method)。

在這里,我們需要理解兩個概念:
模塊模式(The Module Pattern):為單例創建私有變量和方法。
單例(singleton):指的是只有一個實例的對象。JavaScript 一般以對象字面量的方式來創建一個單例對象。

上面是普通模式創建的單例,下面使用模塊模式創建單例:

匿名函數最大的用途是創建閉包,并且還可以構建命名空間,以減少全局變量的使用。從而使用閉包模塊化代碼,減少全局變量的污染。

在這段代碼中函數 addEvent 和 removeEvent 都是局部變量,但我們可以通過全局變量 objEvent 使用它,這就大大減少了全局變量的使用,增強了網頁的安全性。

運用閉包的關鍵

  • 閉包引用外部函數變量對象中的值;
  • 在外部函數的外部調用閉包。

閉包的缺陷

  • 閉包的缺點就是常駐內存會增大內存使用量,并且使用不當很容易造成內存泄露。
  • 如果不是因為某些特殊任務而需要閉包,在沒有必要的情況下,在其它函數中創建函數是不明智的,因為閉包對腳本性能具有負面影響,包括處理速度和內存消耗。

最后 來一道有關閉包的面試題

下面代碼中,標記 ? 的地方輸出分別是什么?

大家結合今天講解的內容,思考一下答案,大家可以把答案發到留意上吧。

好了,今天的講解就那么多,如果你還有什么前端問題想提問的,或者你想李老師下次給大家講什么內容,可以直接關注前端學習公眾號:【網頁前端開發學習】留意提問,說不定下次文章就會講解了。
如果你覺得這篇文章對你有幫助,請轉發點贊支持一下!


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/449994.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/449994.shtml
英文地址,請注明出處:http://en.pswp.cn/news/449994.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

robotframework基礎學習(8)

變量的使用 在 Edit 標簽頁中主要分:加載外部文件、定義內部變量、定義元數據等三個部分。 (1):加載外部文件Add Library:加載測試庫,主要是[PYTHON 目錄]\Lib\site-packages 里的測試庫 Add Resource&…

版本字符串比較工具接口常用接口函數

版本升級比較常用的接口,字符串解析,不是很難,但沒必須重復造輪子,保存一份網上搜到的實現: /*** 比較版本號的大小,前者大則返回一個正數,后者大返回一個負數,相等則返回0** param version1* param version2* return…

[藍橋杯]ALGO-188.算法訓練_P0504

Anagrams指的是具有如下特性的兩個單詞:在這兩個單詞當中,每一個英文字母(不區分大小寫)所出現的次數都是相同的。例如,Unclear和Nuclear、Rimon和MinOR都是Anagrams。編寫一個程序,輸入兩個單詞&#xff0…

什么是3-2混合

正如上面所述,電影轉換成視頻時,每秒24幀必須轉成每秒60場(30幀)。實現這一點的方法是把電影的第一幀顯示3場,然后把第二幀顯示2場,再把第三幀顯示3場,以此類推。這個3-2-3-2-3-2的順序就被稱為…

shell 的here document 用法、輸入/輸出重定向

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 什么是Here Document Here Document 是在Linux Shell 中的一種特殊的重定向方式&#xff0c;它的基本的形式如下 cmd << delimiter…

beta第二天

團隊成員 鄭西坤 031602542 &#xff08;隊長&#xff09; 陳俊杰 031602504陳順興 031602505張勝男 031602540廖鈺萍 031602323雷光游 031602319吳志鴻 0316206341.昨天的困難 陳順興&#xff1a;無 廖鈺萍&#xff1a;無 吳志鴻&#xff1a;沒有 雷光游&#xff1a;無 鄭西坤…

void和void *

void f(void) { // 參數void可以省略cout << "aa"<<endl; } int t 22; int *a &t; void *p; // void *可以被賦值為其他類型 p a; cout << *(int *)p; // 使用的時候必須轉到那個類型 轉載于:https://www.cnblogs.com/pjishu/p/10343587.…

Android應用開發—Application

What is Application Application和Activity&#xff0c;Service一樣是android框架的一個系統組件&#xff0c;當android程序啟動時系統會創建一個application對象&#xff0c;用來存儲系統的一些信息。通常我們是不需要指定一個Application的&#xff0c;這時系統會自動幫我們…

C語言符號

C語言運算符的優先級 一、運算符的優先級表 C 語言的符號眾多&#xff0c;由這些符號又組合成了各種各樣的運算符。既然是運算符就一定有其特定的優先級&#xff0c;下表就是C 語言運算符的優先級表&#xff1a; 注&#xff1a;同一優先級的運算符&#xff0c;運算次序由結合…

手機按鍵中控運行思路的個人理解

目前而言基本的自己理解的中控多線程腳本無非就是兩種1.主代碼作為腳本功能的載體 另外開辟一個線程作為和中控保持聯系的部分(下面只是思路 無法直接運行)Import "zm.luae" zm.Init /* 該思路下的基本流程 從UI界面獲取到云賬號 和 本地的配置信息---->根據自己…

burp過期了,換一個

先從吾愛破解論壇下載工具&#xff1a;https://down.52pojie.cn/Tools/Network_Analyzer/Burp_Suite_Pro_v1.7.37_Loader_Keygen.zip 工具運行需要Java環境&#xff0c;請自行安裝&#xff0c;此處不贅述。解壓完后雙擊keygen 填一下License Text(隨意)&#xff0c;然后點擊Run…

加載一張圖片到ImageView到底占據多少內存

https://blog.csdn.net/BUG_delete/article/details/79557939 簡介 Android中經常要通過ImageView進行圖片資源顯示。在加載圖片時&#xff0c;首先要考慮的兩個因素就是體驗問題和性能問題。 其中&#xff0c;體驗問題是指圖片顯示的是否正確&#xff08;例如Universal-Imag…

mysql -u root -p 解釋

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 mysql -u 用戶名 -p 密碼 是連接數據庫服務器的命令。要求你輸入自己連接數據庫的用戶名和密碼。 考慮密碼如果直接明文寫在這條命令行…

hbase 概念

在hbase里面有幾個通俗的名稱會經常出現 1&#xff09;Hregion region 2&#xff09;Hregionserver regionserver 3&#xff09;Hmaster master 4&#xff09;Hmamstore memstore 5&#xff09;Hfile storeFile 1、什么是hbase&#xff1f; 1&#xff09;它是基于稀疏的、…

beta沖刺第三天

團隊成員 鄭西坤 031602542 &#xff08;隊長&#xff09; 陳俊杰 031602504陳順興 031602505張勝男 031602540廖鈺萍 031602323雷光游 031602319吳志鴻 0316206341.昨天的困難 陳順興&#xff1a;理解別人的代碼 廖鈺萍&#xff1a; 吳志鴻&#xff1a;無 雷光游&#xff1a; …

多線程詳解

1. 進程與線程有那些區別和聯系&#xff1f;   每個進程至少需要一個線程。 進程由兩部分構成&#xff1a;進程內核對象&#xff0c;地址空間。線程也由兩部分組成&#xff1a;線程內核對象&#xff0c;操作系統用它來對線程實施管理。線程堆棧&#xff0c;用于維…

AirPods的自動連接配對原理

首次連接 打開裝有 AirPods 的充電盒&#xff0c;并將它放在 iPhone 旁邊。此時你的 iPhone 上將出現設置動畫。輕點「連接」&#xff0c;然后輕點「完成」。 就這么簡單&#xff0c;而且會自動設置&#xff0c;實現與已使用同一 Apple ID 登錄 iCloud 的任一支持設備搭配使用…

Linux chmod命令

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 Linux/Unix 的文件調用權限分為三級 : 文件擁有者、群組、其他。利用 chmod 可以藉以控制文件如何被他人所調用。 使用權限 : 所有使用…

模塊化

我那進了"模塊化研究"小組.所以嘞.研究模塊化以及如何讓項目的模塊化更加合理和高效是我們小組的主要目的.首先&#xff0c;在實行模塊化之前,得先鞏固模塊化開發的理論基礎,因為理論是實踐的基礎。只有這樣&#xff0c;在過程中理論與實踐相結合,才有可能達到最滿意…

1566:基礎練習 十六進制轉八進制

題目地址&#xff1a;https://acmore.cc/problem/LOCAL/1566 1 #include <iostream>2 #include <string>3 4 using namespace std;5 6 string HexToBin(string s) //16進制轉2進制7 {8 string str "";9 for (int i 0; i < s.size(); i) 10…