Linux 開啟 php_exif
一、為什麼引入閉包
需求:給按鈕新增監聽,要求每次點選時提示點選的是第幾個按鈕
for (var i = 0,length=btns.length; i < length; i++) {
var btn = btns[i]
btn.onclick = function () {
alert('第'+(i+1)+'個')
}
}
上面這段程式碼效果如下
給每個btn標籤的onclick事件執行時,本身onclick繫結的function的作用域中沒有變數i,i為undefined,則解析引擎會尋找父級作用域,發現父級作用域中有i,且for迴圈繫結事件結束後,i已經賦值為4,所以每個btn標籤的onclick事件執行時,alert的都是父作用域中的i,也就是4。這是作用域的問題。
此時可以通過閉包來解決這個問題(使用ES6語法:let宣告i也可以解決這個問題)
for (var i = 0,length=btns.length; i < length; i++) {
(function (j) {
var btn = btns[j]
btn.onclick = function () {
alert('第'+(j+1)+'個')
}
})(i)
}
此時點選每個按鈕後,提示為點選的按鈕的序號。
二、閉包詳解
1.閉包的定義(MDN)
一個函式和對其周圍狀態(lexical environment,詞法環境)的引用捆綁在一起(或者說函式被引用包圍),這樣的組合就是閉包(closure)。也就是說,閉包讓你可以在一個內層函式中訪問到其外層函式的作用域。在 JavaScript 中,每當建立一個函式,閉包就會在函式建立的同時被創建出來。
上面這句話可以拆分理解為以下三句話:
1.閉包是巢狀的內部函式(絕大部分人認為)
2.如何產生閉包? 答:當一個巢狀的內部(子)函式引用了巢狀的外部(父)函式的變數(函式)時, 和執行最外層函式定義就會產生閉包(不用呼叫內部函式)。
function fn1 () {
var a = 2
var b = 'abc'
function fn2 () { //執行函式定義就會產生閉包(不用呼叫內部函式)
console.log(a)
}
}
fn1();
上面這段程式碼在fn1呼叫時就產生了閉包
2.閉包能幹什麼?
閉包常常用來「間接訪問一個變數」。換句話說,「隱藏一個變數」。
閉包可以在函式的外部訪問到函式內部的區域性變數。
還可以讓這些變數始終儲存在記憶體中,不會隨著函式的結束而自動銷燬。
function fn1() {
var a = 2
function fn2() {
a++
console.log(a)
}
return fn2
}
var f = fn1()
f() // 3
f() // 4
上面這段程式碼在呼叫兩次後輸出結果為4是因為 f 對 fn2 的引用使變數a一直儲存在記憶體中。
所以在第二次呼叫 f 時a輸出為4。
此時閉包只產生了一次,因為外部函式只執行了一次(外部函式執行了幾次就有幾個閉包)
問題:
1. 函式執行完後, 函式內部宣告的區域性變數是否還存在? 一般是不存在, 存在於閉中的變數才可能存在
2. 在函式外部能直接訪問函式內部的區域性變數嗎? 不能, 但我們可以通過閉包讓外部操作它
3.閉包的缺點和優點
好處:
①保護函式內的變數安全 ,實現封裝,防止變數流入其他環境發生命名衝突
②在記憶體中維持一個變數,可以做快取(但使用多了同時也是一項缺點,消耗記憶體)
③匿名自執行函式可以減少記憶體消耗
壞處:
①其中一點上面已經有體現了,就是被引用的私有變數不能被銷燬,增大了記憶體消耗,造成記憶體、洩漏,解決方法是可以在使用完變數後手動為它賦值為null;
②其次由於閉包涉及跨域訪問,所以會導致效能損失,我們可以通過把跨作用域變數儲存在區域性變數中,然後直接訪問區域性變數,來減輕對執行速度的影響
4.閉包的應用
自定義JS模組
具有特定功能的js檔案
將所有的資料和功能都封裝在一個函式內部(私有的)
只向外暴露一個包信n個方法的物件或函式
模組的使用者, 只需要通過模組暴露的物件呼叫方法來實現對應的功能
外部JS檔案:
(function () {
//私有資料
var msg = 'Hello World'
//操作資料的函式
function doSomething() {
console.log('doSomething() '+msg.toUpperCase())
}
function doOtherthing () {
console.log('doOtherthing() '+msg.toLowerCase())
}
//向外暴露物件(給外部使用的方法)
window.myModule = {
doSomething: doSomething,
doOtherthing: doOtherthing
}
})()
可以通過以下呼叫來呼叫外部檔案中的方法
myModule.doSomething()
myModule.doOtherthing()
參考:https://blog.csdn.net/weixin_43558749/article/details/90905723