avaScript中除了自定義函數(shù)之外,還有匿名函數(shù)?什么是匿名函數(shù)?
1. 匿名函數(shù):沒有函數(shù)名稱的函數(shù)。
如:定義一個匿名函數(shù),打印5個星星。
<script>
function (){ //沒有函數(shù)名稱
for(var i=0;i<5;i++){
document.write("*");
}
}
</script>
2. 調(diào)用匿名函數(shù)有2種方法:
(1) 通過變量名調(diào)用匿名函數(shù)可以理解為將整個匿名函數(shù)瀆職給一個變量
然后在body標(biāo)簽中,定義一個按鈕:
(2) 事件名調(diào)用匿名函數(shù)
同樣在在body標(biāo)簽中,先定義一個按鈕:注意在input標(biāo)簽中我們不通過onclick來調(diào)用匿名函數(shù)
然后我們通過2個事件調(diào)用2個匿名函數(shù):
注意:window.onload:頁面加載時觸發(fā)的事件,這里也就是頁面加載進(jìn)來調(diào)用第一匿名函數(shù)
document.getElementById("btn"):獲取id為btn的元素,也就是將按鈕獲取過來;document.getElementById("btn").onclick:點(diǎn)擊按鈕時,觸發(fā)第二個匿名函數(shù)
有兩種方式:1、函數(shù)聲明2、函數(shù)表達(dá)式 函數(shù)聲明會提升 ,函數(shù)表達(dá)式不會。閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù),創(chuàng)建閉包的常見方式,是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù),通過另一個函數(shù)訪問這個函數(shù)的局部變量。由于作用域鏈的機(jī)制導(dǎo)致一個問題,循環(huán)里的 匿名函數(shù)取得的任何變量都是最后一個值。閉包所保存的是整個變量對象,而不是某個特殊的變量。this對象 this對象是在運(yùn)行時基于函數(shù)的執(zhí)行環(huán)境綁定的,如果this在全局范圍就是window,如果在對象內(nèi)部就指向這個對象。而閉包卻在運(yùn)行時指向window,因?yàn)殚]包并不屬于這個對象的屬性或方法。
有兩種方式:1、函數(shù)聲明2、函數(shù)表達(dá)式
函數(shù)聲明會提升,函數(shù)表達(dá)式不會。
函數(shù)聲明,在執(zhí)行函數(shù)之前會先讀取函數(shù)聲明。
sayhi()//‘hi’ function sayhi(){ console.log('hi'); } //不會出錯
函數(shù)表達(dá)式
sayhi()//‘hi’ var sayhi=function(){ console.log('hi'); } //會出錯
函數(shù)表達(dá)式和函數(shù)聲明中沒有函數(shù)名的函數(shù),都是匿名函數(shù)
//不要這樣做!,有的瀏覽器用第一個聲明,有的用第二個 if(condition){ function sayHi(){ alert("Hi!"); } } else { function sayHi(){ alert("Yo!"); } } //可以這樣做 var sayHi; if(condition){ sayHi = function(){ alert("Hi!"); }; } else { sayHi = function(){ alert("Yo!"); }; }
閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù),創(chuàng)建閉包的常見方式,是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù),通過另一個函數(shù)訪問這個函數(shù)的局部變量。
閉包可以讓外側(cè)函數(shù)的局部變量駐留內(nèi)存,實(shí)現(xiàn)局部變量的累加,過度使用閉包導(dǎo)致性能下降,內(nèi)存泄漏
function a(){ var age=1; return function(){ age++; return age; } } var x=a(); console.log(x())//2 console.log(x())//3
由于作用域鏈的機(jī)制導(dǎo)致一個問題,循環(huán)里的匿名函數(shù)取得的任何變量都是最后一個值。閉包所保存的是整個變量對象,而不是某個特殊的變量。
function box() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = function() { return i; }; } return arr; } var b = box(); //得到函數(shù)數(shù)組 alert(b.length); //得到函數(shù)集合長度 for (var i = 0; i < b.length; i++) { console.log(b[i]()); //輸出每個函數(shù)的值,都是最后一個值55555 }
因?yàn)閎中存的是匿名函數(shù)對象,當(dāng)bi執(zhí)行匿名函數(shù)時,box()中的for循環(huán)早已執(zhí)行完畢,i早已變成5.
解決方法1:讓匿名函數(shù)自我執(zhí)行
function box() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = (function(i) { return i; })(i); } return arr; } var b = box(); //得到函數(shù)數(shù)組 alert(b.length); //得到函數(shù)集合長度 for (var i = 0; i < b.length; i++) { console.log(b[i]); //輸出0,12,3,4 }
解決方法2:匿名函數(shù)下在創(chuàng)建一個匿名函數(shù),外側(cè)匿名函數(shù)自執(zhí)行
function box() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = (function(num) { return function() { return num;//具體數(shù)字 }; })(i) } return arr; } var b = box(); //得到函數(shù)數(shù)組 alert(b.length); //得到函數(shù)集合長度 for (var i = 0; i < b.length; i++) { console.log(b[i]()); //輸出 01234 }
this對象是在運(yùn)行時基于函數(shù)的執(zhí)行環(huán)境綁定的,如果this在全局范圍就是window,如果在對象內(nèi)部就指向這個對象。而閉包卻在運(yùn)行時指向window,因?yàn)殚]包并不屬于這個對象的屬性或方法。
var user='window'; var obj={ user:'obj', getUserName:function(){ return function(){ return this.user; } } } console.log(obj.getUserName()());//window
解決1:強(qiáng)制指向特定對象
console.log(obj.getUserName().call(obj));//obj console.log(obj.getUserName().apply(obj));//obj
解決2:復(fù)制this,得到上一個作用域的this對象
var user='window'; var obj={ user:'obj', getUserName:function(){ var that=this; return function(){ return that.user; } } } console.log(obj.getUserName()());//obj
for循環(huán)中的var i
在外部也能訪問
function box(count) { for (var i=0; i<count; i++) {} var i; //就算重新聲明,也不會覆蓋前面的值,除非重新初始化 alert(i); } box(2);//2
解決1:
//模仿塊級作用域(私有作用域)
(function () {
//這里是塊級作用域
})();
//使用塊級作用域(私有作用域)改寫 function box(count) { (function () { for (var i = 0; i<count; i++) {} })(); alert(i); //報錯,無法訪問 } box(2);
解決2:ES6中使用let
function box(count) { for (let i=0; i<count; i++) {} alert(i); //i報錯 } box(2);
參考資料:JavaScript高級程序設(shè)計(第3版)
數(shù)的編寫與使用
在程序設(shè)計語言中函數(shù)是一段具有特殊功能的代碼,同時也是一組可以重復(fù)使用的代碼。通過函數(shù)這一對象的使用,進(jìn)一步提高了程序開發(fā)的模塊化與高度多的代碼復(fù)用性。各種程序設(shè)計語言都對函數(shù)的定義及使用有著嚴(yán)格的語法規(guī)則。本文主要介紹如何在JavaScript中定義函數(shù)、使用函數(shù),并對遞歸函數(shù)這一特殊類型函數(shù)進(jìn)行說明。
JavaScript中所定義的函數(shù)主要由函數(shù)定義關(guān)鍵字、函數(shù)名稱、函數(shù)參數(shù)、執(zhí)行代碼段與函數(shù)返回值5部分所組成。同時要求函數(shù)在使用過程中需要先定義函數(shù),再調(diào)用函數(shù)。JavaScript函數(shù)定義基本語法描述如下:
JavaScript函數(shù)定義基本語法
JavaScript函數(shù)定義基本語法描述如上圖,說明如下:
函數(shù)定義語法說明
函數(shù)定義完成之后,就可以通過調(diào)用該函數(shù)完成特定的功能。函數(shù)調(diào)用方式較為簡單,只需要給出函數(shù)名稱與所傳遞參數(shù),如果參數(shù)為空,只需要給出名稱后面的括號即可。關(guān)于參數(shù)部分需要注意形參與實(shí)參概念的區(qū)分。其中在函數(shù)定義中用于解釋說明語言的參數(shù)為形參。在函數(shù)調(diào)用過程中替代形參參與實(shí)際運(yùn)算的參數(shù)為實(shí)參。示例說明如下:
形參與實(shí)參示例說明
匿名函數(shù)(Anonymous function),顧名思義是指沒有名字的函數(shù),即在上面給出的基本語法中functionName部分可以省略的函數(shù)。在JavaScript中提供兩類基本匿名函數(shù)定義方式,一種是將匿名函數(shù)封裝為表達(dá)式,一種是將匿名函數(shù)賦值給變量形式。兩類匿名函數(shù)基本語法描述如下:
匿名函數(shù)的定義形式
匿名函數(shù)定義形式描述如上圖所示,上文中計算解決值函數(shù)我們可以使用兩種方法改寫為匿名函數(shù),實(shí)現(xiàn)描述如下:
匿名函數(shù)使用實(shí)例
遞歸函數(shù)是一類特殊的函數(shù)類型,簡單理解即為在一個函數(shù)的內(nèi)部調(diào)用了該函數(shù)自身。在使用遞歸函數(shù)是需要注意產(chǎn)生遞歸的條件與遞歸終止的條件。如同循環(huán)控制語句一樣,沒有遞歸終止的條件,程序?qū)恢闭加觅Y源,無法結(jié)束釋放資源。遞歸函數(shù)的說明可以從階乘的計算這一案例展開說明。階乘計算過程描述如下:
階乘計算原理
階乘計算過程描述如上圖所示,我們可知階乘問題的解決主要在于遞推關(guān)系的挖掘與終止條件的確定。本例中遞推關(guān)系為N!=N*(N-1)!,終止條件為1!=1;在明確這兩點(diǎn)之后我們可以編寫遞歸函數(shù)實(shí)現(xiàn)問題求解。遞歸函數(shù)描述如下圖:
階乘問題的遞歸求解編程實(shí)現(xiàn)
爬樓梯問題是使用遞歸算法進(jìn)行問題求解的經(jīng)典案例之一,爬樓梯問題主要只是假設(shè)有N階樓梯,需要從最底層爬到最高層,在上樓過程中每步只允許上1層或者2層,計算爬到N層總共方法有多少種?
爬樓梯方法問題
爬樓梯方法問題采用遞歸思想還是比較簡單的,我們可以從小人最后一步考慮。小人上到最高層N層時只能有兩種方法:
①從N-2層跨越2層到達(dá)N層;
②從N-1層跨越1層到達(dá)N層;
則計算到達(dá)N層的方法f(n)就等于到達(dá)N-1層方法f(n-1)與達(dá)N-2層方法f(n-2)之和。這就找到了我們進(jìn)行遞推的關(guān)系式,終止條件即為f(1)=1和f(2)=2;
因此我們可以編程實(shí)現(xiàn)計算,實(shí)現(xiàn)代碼如下:
爬樓梯遞歸求解代碼
本頭條號長期關(guān)注編程資訊分享;編程課程、素材、代碼分享及編程培訓(xùn)。如果您對以上方面有興趣或代碼錯誤、建議與意見,可以聯(lián)系作者,共同探討。更多程序設(shè)計相關(guān)教程及實(shí)例分享,期待大家關(guān)注與閱讀!JavaScript基礎(chǔ)教程系列教程鏈接如下:
JavaScript基礎(chǔ)教程(六)流程控制之循環(huán)語句
JavaScript基礎(chǔ)教程(五)流程控制之條件語句
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。