關於閉包
什麼是閉包?
閉包:
一個函數和詞法環境的引用捆綁在一起,這樣的組合就是閉包
就是一個函數A,return其內部的函數B,被return出去的函數B能夠在外部訪問A函數內部的變數(定義在函數內部的函數)
這時候就形成了一個函數B的變數背包,A函數執行結束之後這個變數背包也不會被銷毀
並且這個變數背包在A函數外部只能通過B函數來訪問(閉包就是一座將函數內部和外部連接起來的橋樑)
原理:
作用域鏈,當前作用域鏈可以訪問上級作用域中的變數
閉包解決的問題:
能夠讓函數作用域中的變數在函數執行結束之後不被銷毀,同時也能在函數外部可以訪問函數內部的局部變數。
閉包帶來的問題:
由於垃圾回收機制不會將閉包中的變數銷毀,記憶體消耗會很大,所以不能濫用閉包,否則會造成網頁性能問題,
也可能導致記憶體泄露,記憶體泄露積累多了就容易導致記憶體溢出(解決辦法是在退出函數之前,將不使用的局部變數全部刪除)
閉包的主要作用:
模仿塊級作用域:
已知數組var arr = ['a','b','c','d','e','f'],每過1秒列印一下數組中的值:
未有塊級作用域時:setTimeout屬於非同步任務,for循環結束後,每秒輸出的都為 'e'
var arr = ["a", "b", "c", "d", "e"]; for (var i = 0; i < arr.length; i++) { var item = arr[i]; setTimeout(function() { console.log(item); }, 1000 * (i + 1)); }
ES5:藉助IIFE(彌補JS在scope方面的缺陷)
var arr = ["a", "b", "c", "d", "e"]; for (var i = 0; i < arr.length; i++) { (function(j){ var item = arr[j]; setTimeout(function() { console.log(item); }, 1000 * (j + 1)); })(i); }
ES6:let、const塊級作用域
var arr = ["a", "b", "c", "d", "e"]; for (let i = 0; i < arr.length; i++) { const item = arr[i]; setTimeout(function() { console.log(item); }, 1000 * (i + 1)); }
實現柯里化:
柯里化是一種轉換,將 f(a,b,c) 轉換為可以被以 f(a)(b)(c) 的形式進行調用。
在構造函數中定義特權方法:
有權訪問私有變數、私有函數的公有方法就是特權方法
Vue中數據響應式Observe中使用閉包等:
function defineRealive(target, key, value){ return Object.defineProperty(target, key, { get(){ console.log(`通過getter獲取數據:${value}`); return value; }, set(val){ console.log(`通過setter設置數據:新值-${val};舊值-${value}`); // 形參也是一個普通的局部變數,只是可能我們平時使用的時候,一般不會對形參進行賦值操作,因為大部分情況,形參都是外部傳入的數據,我們無需修改。 // 這裡就用到了閉包的原理,value是外層函數defineRealive的參數,而我們實際上使用value確是在內層的get或set方法裡面 // 這樣就形成了一個閉包的結構了。根據閉包的特性,內層函數可以引用外層函數的變數,並且當內層保持引用關係時外層函數的這個變數 // 不會被垃圾回收機制回收。那麼,我們在設置值的時候,把val保存在value變數當中,然後get的時候再通過value去獲取,這樣,我們再訪問 // obj.name,無論是設置值還是獲取值,實際上都是對value這個形參進行操作的。 value = val; } }); } let obj = { name: 'kiner', age: 20 }; Object.keys(obj).forEach(key=>defineRealive(obj, key, obj[key])); obj.name = 'kanger'; obj.age = 18; // 控制台輸出:kanger 18 console.log(obj.name,obj.age);
記憶體泄露與記憶體溢出:
記憶體泄露是指程式中已動態分配的堆記憶體由於某種原因,程式未釋放或無法釋放,造成的記憶體浪費
導致程式運行速度減慢甚至系統崩潰等嚴重後果(即不再會被使用的對象的記憶體不能被回收)
記憶體泄後堆積的結果就是記憶體溢出
參考:

