您好,登錄后才能下訂單哦!
這篇文章主要介紹了JavaScript閉包喲哪些用途及怎么實現的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇JavaScript閉包喲哪些用途及怎么實現文章都會有所收獲,下面我們一起來看看吧。
當通過調用外部函數返回的內部函數后,即使外部函數已經執行結束了,但是內部函數引用了外部函數的變量依然會保存在內存中,我們把這些變量的集合,稱為閉包(Closure)。
在了解閉包的概念和用途之前,理解作用域和變量的生命周期等基礎預備知識,對于理解閉包非常有幫助。
閉包是指一個函數可以訪問它定義時所在的詞法作用域以及全局作用域中的變量。在JavaScript中,閉包可以通過函數嵌套和變量引用實現。
function outerFunction() { let outerVariable = '我在outer函數里!'; function innerFunction() { console.log(outerVariable); } return innerFunction; } const innerFunc = outerFunction(); innerFunc(); // 輸出: 我在outer函數里!
在上面的代碼示例中,innerFunction
引用了outerVariable
,因此JavaScript引擎會保留outerFunction
的作用域鏈,以便innerFunction
可以訪問outerVariable
。
function a(){ function b(){ var bb = 888 console.log(aa); //輸出:666 } var aa = 666 return b } var demo = a() demo()
在上面的代碼示例中,a
函數定義了一個名為aa
的變量和一個名為b
的函數,b
函數引用了aa
變量,因此JavaScript引擎會保留a
函數的作用域鏈,b
函數可以訪問a
函數的執行上下文,b
函數內用到了外部函數a
的變量aa
,在a
函數調用結束后該函數執行上下文會銷毀,但會保留一部分留在內存中供b
函數使用,這就形成了閉包。
具體來說,當內部函數引用外部函數的變量時,外部函數的作用域鏈將被保留在內存中,以便內部函數可以訪問這些變量。 這種函數嵌套和變量共享的方式就是閉包的核心概念。當一個函數返回另一個函數時,它實際上返回了一個閉包,其中包含了原函數定義時的詞法作用域和相關變量。
閉包可以用于封裝私有變量,以防止其被外部訪問和修改。封裝私有變量可以一定程度上防止全局變量污染,使用閉包封裝私有變量可以將這些變量限制在函數內部或模塊內部,從而減少了全局變量的數量,降低了全局變量被誤用或意外修改的風險。
在下面這個例子中,調用函數,輸出的結果都是1,但是顯然我們的代碼效果是想讓count
每次加一的。
function add() { let count = 0; count++; console.log(count); } add() //輸出1 add() //輸出1 add() //輸出1
一種顯而易見的方法是將count
提到函數體外,作為全局變量。這么做當然是可以解決問題,但是在實際開發中,一個項目由多人共同開發,你不清楚別人定義的變量名稱是什么,這么做有點冒險,有什么其他的辦法可以解決這個問題呢?
function add(){ let count = 0 function a(){ count++ console.log(count); } return a } var res = add() res() //1 res() //2 res() //3
答案是用閉包。在上面的代碼示例中,add
函數返回了一個閉包a,其中包含了count
變量。由于count
只在add
函數內部定義,因此外部無法直接訪問它。但是,由于a
函數引用了count
變量,因此count
變量的值可以在閉包內部被修改和訪問。這種方式可以用于封裝一些私有的數據和邏輯。
函數一旦被執行完畢,其內存就會被銷毀,而閉包的存在,就可以保有內部環境的作用域。
function foo(){ var myName ='張三' let test1 = 1 const test2 = 2 var innerBar={ getName: function(){ console.log(test1); return myName }, setName:function(newName){ myName = newName } } return innerBar } var bar = foo() console.log(bar.getName()); //輸出:1 張三 bar.setName('李四') console.log(bar.getName()); //輸出:2 李四
這里var bar = foo() 執行完后本來應該被銷毀,但是因為形成了閉包,所以導致foo執行上下文沒有被銷毀干凈,被引用了的變量myName、test1沒被銷毀,閉包里存放的就是變量myName、test1,這個閉包就像是setName、getName的專屬背包,setName、getName依然可以使用foo執行上下文中的test1和myName。
閉包還可以用于實現模塊化編程。模塊化編程是一種將程序拆分成小的、獨立的、可重用的模塊的編程風格。閉包可以用于封裝模塊的私有變量和方法,以便防止其被外部訪問和修改。例如:
const myModule = (function() { let privateVariable = '我是私有的!'; function privateMethod() { console.log(privateVariable); } return { publicMethod: function() { privateMethod(); } }; })(); myModule.publicMethod(); // 輸出: 我是私有的!
在上面的代碼示例中,myModule實際上是一個立即執行的匿名函數,它返回了一個包含publicMethod的對象。在函數內部,定義了一個私有變量privateVariable和一個私有方法privateMethod。publicMethod是一個公共方法,它可以訪問privateMethod,但是無法訪問privateVariable。這種方式可以用于實現簡單的模塊化編程。
閉包也存在著一個潛在的問題,由于閉包會引用外部函數的變量,但是這些變量在外部函數執行完畢后沒有被釋放,那么這些變量會一直存在于內存中,總的內存大小不變,但是可用內存空間變小了。 一旦形成閉包,只有在頁面關閉后,閉包占用的內存才會被回收,這就造成了所謂的內存泄漏。
因此我們在使用閉包時需要特別注意內存泄漏的問題,可以用以下兩種方法解決內存泄露問題:
1.及時釋放閉包:手動調用閉包函數,并將其返回值賦值為null,這樣可以讓閉包中的變量及時被垃圾回收器回收。
2.使用立即執行函數:在創建閉包時,將需要保留的變量傳遞給一個立即執行函數,并將這些變量作為參數傳遞給閉包函數,這樣可以保留所需的變量,而不會導致其他變量的內存泄漏。
關于“JavaScript閉包喲哪些用途及怎么實現”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“JavaScript閉包喲哪些用途及怎么實現”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。