函數用來封裝須要屢次使用的代碼塊數組
函數也是一個對象,所以能夠給函數添加屬性和方法,並做爲數據值(利用函數的返回值)/參數(特定函數如setTimeout)/返回值使用app
把函數當參數傳遞時,函數名即爲函數本體(裏面的代碼塊),無需添加括號(添加括號即爲執行函數)ide
當函數做爲返回值時,爲了調用返回的函數,須要在函數本體(函數名)後加()來執行函數
函數包括函數名、形式參數、實際參數、返回值this
函數名是指向函數在內存中位置的介質,可省略(此時叫匿名函數)spa
定義函數時函數名後的括號裏即爲形式參數(形參),不是必填,且形參和實參的數目沒必要相等code
使用函數時實際傳入的參數爲實際參數(實參)對象
函數內部return後的語句即返回值blog
函數使得代碼得以複用(不須要屢次Ctrl+C、Ctrl+V複製粘貼,只要調用函數便可使用相同的代碼塊執行特定功能)遞歸
便於代碼的維護和修改(只需在函數中修改代碼便可,調用函數的地方隨之修改)
增長程序的可讀性(把實現方法的細節封裝在函數中,用函數名來表示實現的方法,更易理解)
包括function聲明和var賦值表達式
1 function add(){ 2 console.log('I like swimming'); 3 }
1 var add = function(){ 2 console.log('I like swimming'); 3 }
function聲明函數會預解析,執行函數放在函數定義前也能夠順利執行(聲明提早)
var賦值表達式定義函數,在預解析時會將變量賦值爲undefined,若是執行函數的操做在定義函數前,則報錯
構建一個function對象的實例,其中形參和代碼塊都放在引號中
var add = new Function('num1','num2','return num1+num2;');
函數可定義在全局環境或局部環境(函數/對象內部)中
在全局中定義的函數,在全局內部任意位置均可以找到並調用這個函數
在局部中定義的函數,只可經過做用域鏈,向上一層找到該函數,若是找不到則報錯
1.將其賦值給一個變量,用變量名()來實現調用
1 var add = function(){ 2 alert(1); 3 } 4 add();
2.直接用函數本體後加()的形式自我執行
這裏的原理是:用function聲明的函數會被識別並預解析,而在function前加合法的符號(+-!~等),不讓函數以function打頭,則函數不會被預解析,從而實現自執行
所以,在執行的()外/內加一組括號都是能夠的
1 !+-~function(){ 2 alert(1); 3 }();
1 (function (){ 2 alert(1); 3 })();
可是要注意,自執行的函數也是有做用域的,執行完畢後,內部的做用域被銷燬
在函數內部調用自身
注意調用次數不要超過最大的遞歸層數
1 function factorial(num){ 2 if(num == 1){ 3 return 1; 4 } 5 else{ 6 return num*factorial(num-1); 7 } 8 } 9 console.log(factorial(5));
不合法的方法名(屬性名)須要用引號括起來(例如@),調用時用[](例如add['@'](1,2))
若是調用的方法名是一個字符串,則也使用[]
方法也能夠鏈式調用,但該對象裏的每一個方法須要返回當前對象(不然會形成undefined.方法的結果,出現報錯)
不推薦過分使用鏈式調用
1 var operation = { 2 add:function(num1,num2){ 3 console.log(+num1+ +num2); 4 return this; 5 }, 6 subtract:function(num1,num2){ 7 console.log(num1-num2); 8 return this; 9 } 10 } 11 operation.add(1,2).subtract(3,2);
經過new 構造函數名()來調用(例如new Object())
調用完成後返回一個對象(該構造函數實例化的對象)
即不使用函數中的方法名()來調用方法,而是用函數名.方法名.apply()/call()來間接調用方法
注意此處函數名後不可跟()
call和apply方法的第一個參數都是用來改變方法中this的指向的,第二個參數apply可接收一個數組,把數組中每一個元素做爲參數傳入,而call只可接收一個個獨立的參數
形式參數(形參):聲明函數時的‘佔位用’參數(在預解析時被當作函數的局部變量),可用函數名.length屬性來訪問到其個數
實際參數(實參):調用函數時傳入的參數,可用arguments.length屬性訪問其個數
參數傳遞的本質:實參賦值給形參
1.實參數目=形參數目:按照定義函數時的順序,把實參一一賦值給形參
2.實參數目<形參數目:未被賦值的形參爲undefined
通常會在有可選參數時使用(若是不傳遞某個參數,給這個參數默認值)
1 function power(base,power){ 2 if(!power){ 3 power = 2; 4 } 5 return Math.pow(base,power); 6 } 7 console.log(power(3));//返回的是9
3.實參數目>形參數目:多餘的實參不被歸入函數的調用範圍,會正常運行
arguments裏保留了全部的實參(以鍵值對形式存儲)、length屬性、callee方法
建議不要在函數中對arguments對象進行修改操做
callee方法能夠返回arguments對象的函數,防止函數名變化時,內部遞歸調用的函數名稱也須要同時改變(嚴格模式下callee方法不可用)
1 function jiecheng(num){ 2 if(num == 1){ 3 return 1; 4 } 5 else{ 6 return num*arguments.callee(num-1); 7 } 8 } 9 console.log(jiecheng(5));
嚴格模式下,能夠把命名函數賦值給經過var聲明的變量,來達到相似callee的效果(變量名變化時,函數名以及函數內部自調用的名稱都不要變,只要改變變量名)
1 var jiecheng = function f1(num){ 2 if(num == 1){ 3 return 1; 4 } 5 else{ 6 return num*f1(num-1); 7 } 8 } 9 console.log(jiecheng(5));
1.參數能夠爲空(聲明函數時,括號中能夠爲空)
2.能夠經過做用域鏈,用上一級的局部變量/全局變量來做爲函數的參數
3.能夠傳遞基本類型數據(數字、字符串、布爾值、undefined、null)或引用類型數據(數組、對象(參數三個以上時推薦使用)、函數)
其中傳入對象能夠解決了參數傳遞時必須按照形參順序的問題
函數結束,將後續的內容返回(不然返回undefined)
1.返回值能夠爲空,即函數到此終止,返回undefined
2.返回值可爲基本類型數據(數字、字符串(alert函數)、布爾值、undefined、null)、引用數據類型(數組、對象、函數)
document.write()方法指望返回的是字符串,若是不是,會調用toString方法將其返回爲字符串