javascript
解析面试常问题之JavaScript中的闭包概念及应用,顺便普及一下大家口中常说的内存泄漏问题
JavaScript中的閉包是一個面試中經(jīng)常被考到的問題,大家可能都對這個概念多多少少都有一些模糊的概念或者一點都不了解,那么今天就來給大家講解一下。
- 公眾號:前端印象
- 不定時有送書活動,記得關(guān)注~
- 關(guān)注后回復(fù)對應(yīng)文字領(lǐng)取:【面試題】、【前端必看電子書】、【數(shù)據(jù)結(jié)構(gòu)與算法完整代碼】、【前端技術(shù)交流群】
JavaScript之閉包
- 一、引言
- 二、閉包的定義
- 三、體驗閉包
- 三、使用閉包的注意事項
- 四、內(nèi)存泄漏
- 五、閉包的私有變量
- 六、總結(jié)
- 七、結(jié)束語
一、引言
首先在這里我得說一下,要了解閉包一定要有作用域鏈的相關(guān)概念,這里我放上一篇文章,希望大家花3分鐘看一下,了解一下作用域鏈,否則后面看起來會有點懵。作用域鏈講解文章——從零開始講解JavaScript中作用域鏈的概念及用途
二、閉包的定義
閉包: 是指有權(quán)訪問另一個函數(shù)作用中的變量的函數(shù),常見的閉包形式就是一個函數(shù)的內(nèi)部再創(chuàng)建另一個函數(shù)。
想必這個概念聽起來很懵,那我們接下來就來體驗一個閉包吧。
三、體驗閉包
來用一個小案例,來體驗一下閉包是什么
<!DOCTYPE html> <html> <head><meta charset="UTF-8"><title></title> </head><body><div class="show">0</div> <button>增加</button><script>let show = document.querySelector('.show')let btn = document.querySelector('button')function func() {let n = 0btn.onclick = function () {n ++show.innerHTML = n}}f() </script></body> </html>接下來是gif動圖展示
我們可以看到,在函數(shù) fnc 中定義了一個變量 n,而我們在該函數(shù)內(nèi)部,對按鈕 btn 綁定了一個點擊函數(shù),該點擊函數(shù)將變量 n + 1,然后展示在頁面上。了解過作用域鏈的小伙伴會知道,當(dāng)我們點擊按鈕的時候,處罰了點擊的處理函數(shù),此時該函數(shù)內(nèi)部的作用域鏈是這個樣子的
引用了變量 n ,首先在作用域鏈的第一個變量對象中尋找變量 n,沒有找到;然后去作用域鏈的第二個里尋找變量 n,找到了,也就是在函數(shù) func 內(nèi)部定義的變量 n。所以該點擊處理函數(shù)每次引用變量 n 時,都是從函數(shù) func 內(nèi)部去尋找的變量 n ,這也就是我們所說的,一個函數(shù)有權(quán)訪問另一個函數(shù)內(nèi)部的變量。
三、使用閉包的注意事項
上面我們了解了閉包的基本使用,那么我們再用一個例子來給大家介紹在使用閉包時容易犯的錯誤。
function create() {var arr = []for(var i=0; i<10; i++) {arr[i] = function () {return i}}return arr }let result = create()result[0]() //返回10 result[1]() //返回10 …… result[9]() //返回10這個例子就是在函數(shù) create 中通過 for 循環(huán)定義10個匿名函數(shù),每個函數(shù)都返回變量 i,最終將每個匿名函數(shù)保存到數(shù)組 arr 中并返回數(shù)組 arr,然后我們在收到數(shù)組 arr 后依次調(diào)用每個匿名函數(shù),發(fā)現(xiàn)每個返回的都是數(shù)字10,而我們最初的目的是依次返回的是 0~9。
這是因為,我們調(diào)用匿名函數(shù)的時候需要返回變量 i ,而匿名函數(shù)內(nèi)部沒有該變量,所以去往下一個變量對象,也就是定義匿名函數(shù)時所處的函數(shù)環(huán)境 create 中尋找變量 i ,但此時的變量 i 已經(jīng)通過循環(huán)變成了10,所以當(dāng)我們調(diào)用每個匿名函數(shù)時,返回的全部都是10.
為此,我們的代碼可以寫成這樣
function create() {var arr = []for(var i=0; i<10; i++) {arr[i] = (function (num) {return function () {return num}})(i)}return arr }let result = create()result[0]() //返回 0 result[1]() //返回 1 …… result[9]() //返回 9這樣做就直接在定義最內(nèi)部的匿名函數(shù)時,把當(dāng)前循環(huán)的變量 i 放在了最內(nèi)部匿名函數(shù)外部的那個匿名函數(shù)內(nèi),這樣的話,我們之后調(diào)用匿名函數(shù)時,尋找變量 i 就會從該匿名函數(shù)外部的那個匿名函數(shù)的變量對象中找到相應(yīng)的變量。
四、內(nèi)存泄漏
相信面試過的小伙伴都知道,在面試時,如果面試官問到你閉包,可能會跟你提一下內(nèi)存泄漏。
首先我要打假一個說法,很多人都說閉包會引起內(nèi)存泄漏,這一半真一半假,因為只有在IE9之前才會因為閉包出現(xiàn)內(nèi)存泄露的問題,所以以后千萬別在別人面前說閉包就會引起內(nèi)存泄露了哈。
那么內(nèi)存泄露到底是什么呢?
簡單來說一下,就是當(dāng)一個閉包的作用域鏈內(nèi)有一個HTML元素時,該元素就無法被垃圾回收機制給銷毀。
這里不懂JavaScript垃圾回收機制的小伙伴可以花2分鐘看一下這篇文章,下面會講解到,以防聽不懂——JavaScript的垃圾回收機制,清除無用變量,釋放多余內(nèi)存,展現(xiàn)更好的性能
function handle() {let element = document.querySelector('#app')element.onclick = function () {console.log(element.id)} }在函數(shù) handle 中,給HTML元素 element 創(chuàng)建了一個點擊事件的匿名函數(shù),該函數(shù)內(nèi)部引用了變量 element ,所以變量 element 的引用次數(shù)為1,這樣的話垃圾回收機制一直都不會清除該元素了,這就是一個內(nèi)存泄露的情況。
所以我們可以這樣做,來解決內(nèi)存泄露的問題
function handle() {let element = document.querySelector('#app')let id = element.idelement.onclick = function () {console.log(id)}element = null }將元素 element 的 id 值保存在一個變量 id 內(nèi),然后在該元素的點擊處理事件中引用變量 id , 并且在最后通過把變量 element設(shè)置為 null ,以解除對DOM元素的引用,這樣引用次數(shù)就變?yōu)?,而不再是1了,垃圾回收機制就可以對其進行清除了。
五、閉包的私有變量
顧名思義,私有變量的意思就是說,閉包擁有自己的變量,別人都無法訪問,無法使用。
很明顯,了解過作用域鏈就能清楚得知道,當(dāng)函數(shù)調(diào)用后,作用域鏈是先從最內(nèi)部開始,然后向外依次排列。所以只有內(nèi)部訪問外部變量的說法,而沒有說外部訪問內(nèi)部變量的道理。
就比如這個簡單的例子
let m = 1 let n = 4function func() {let n = 2alert(m) //返回 1return function () {let m = 3alert(n) //返回 2} }func()在該例子中可以看到,函數(shù) func 本意想訪問匿名函數(shù)中的變量 m 值為3,但卻只訪問到全局中的變量 m 值為1;而匿名函數(shù)就成功訪問到了函數(shù) func 內(nèi)部定義的變量 n 值為2
這就是通過閉包實現(xiàn)的私有變量的例子
六、總結(jié)
- 閉包就是指有權(quán)訪問另一個函數(shù)作用中的變量的函數(shù),常見的閉包形式就是一個函數(shù)的內(nèi)部再創(chuàng)建另一個函數(shù)。
- 閉包就是為了隱藏變量,使外部無法訪問到
- 閉包可以將變量定義在內(nèi)部,使內(nèi)部擁有自己的變量,同時可以不污染全局變量
七、結(jié)束語
想必這篇文章應(yīng)該能讓你對閉包的概念有了很深的理解了。
希望這篇文章能對你們有所幫助,我是Lpyexplore,創(chuàng)作不易,喜歡的加個關(guān)注,點個收藏,給個贊~
總結(jié)
以上是生活随笔為你收集整理的解析面试常问题之JavaScript中的闭包概念及应用,顺便普及一下大家口中常说的内存泄漏问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用电脑却要安装Linux系统的五个理由
- 下一篇: 20220712 初识JS