函數表達式和閉包 針對JS高級程式設計這本書,主要是理解概念,大部分內容源自書內。寫這個主要是當個書中的筆記加總結 存在的問題請大家多多指正! 定義函數的兩種方法 函數聲明: 函數表達式: 函數聲明提升 :函數可以先用,聲明在下麵自動給提到上面來 函數表達式 後面的是 匿名函數 ,又叫 拉姆達函數 ...
函數表達式和閉包
針對JS高級程式設計這本書,主要是理解概念,大部分要點源自書內。寫這個主要是當個筆記加總結
存在的問題請大家多多指正!
定義函數的兩種方法
函數聲明:
function functionName(arg0,arg1,arg2){
//函數體
}
函數表達式:
var functionName = function(arg0, arg1, arg2){
//函數體
}
函數聲明提升:函數可以先用,聲明在下麵自動給提到上面來
函數表達式=
後面的是匿名函數,又叫拉姆達函數,他一般可以被用來當成值使用(可以用來return
)
遞歸
函數自己調用自己就叫遞歸,沒啥好說的。當函數賦值給另一個函數時會導致重新調用函數名稱不同而調用失敗
var anotherFactorial = factorial //factorial是一個遞歸函數
factorial = null
alert(anotherfactorial(5))//error
所以在函數內部自己調用自己的時候不要使用自己的函數名,應該用耦合度更大的arguments.callee來表示自己的函數名,例如
fucntion factorial(num){
if(num <= 1){
return 1
} else {
//此處arguments.callee代替函數名factorial
return num * arguments.callee(num-1)
}
}
閉包
總結來說就是指有許可權訪問另一個函數作用域中的變數的函數
常見的方式就是在一個函數內部創建另一個函數。
先看一波閉包的效果:
//creatComparisonFunction是下麵要說的外層函數
var compareNames = creatComparisonFunction('name')
//compareNames在調用的就是閉包函數方法了,為什麼對象能夠使用方法,因為閉包返回的是一個方法
var result = compareNames({ name: 'laotie' },{ name: '6666'})
仔細的說的話在一個函數里的return出來的匿名函數就叫閉包。在作用域鏈中一個函數內部的函數可以訪問他鏈後面(鏈後面指當前活動對象的外層,也就是內層函數外層的函數)對象的參數,然而當外面函數執行完了,裡面的函數就不能再去調用外層函數的數據了,這是因為當一個函數執行完畢時,局部活動的對象就會被銷毀,當外層函數執行完後里不僅內層函數被銷毀,順帶著外層函數的數據也被銷毀了。然而通過閉包可以實現一種效果,外層函數執行完了以後,內層函數再次調用的話還可以調用外層函數的屬性。
因為太抽象了,所以書中給了一個例子:
//createComparisonFunction 就是一個外層函數,他傳進來一個propertyName的參數
function createComparisonFunction(propertyName){
return function(object1,object2){
//這時候內層調用了外層的參數,理論上不用閉包也行的,但是閉包的目的是當外層函數執行完了,還可以有機會去執行內層函數並使用外層函數的參數
var value1 = object1[propertyName]
var value2 = object2[propertyName]
if(value1 < value2){
return -1
} else if (value1 > value2){
return 1
} else {
return 0
}
}
}
上面例子中return 的function就是閉包函數,閉包實現'外層函數執行完了以後,內層函數再次調用的話還可以調用外層函數的屬性的'這種效果主要是因為匿名函數的作用域鏈中包含他的外層函數,因為匿名函數的作用域鏈始終引用著他外層函數的活動對象,所以除非接觸匿名函數的引用,否則外層函數的活動對象會一直存在。這也引起來閉包會比較占記憶體,所以要慎重使用。
//跟上第一個例子:解除對匿名函數的引用
compareNames = null