從功能上理解,函數是一組能夠隨時運行的語句,是一段代碼塊,也是所謂的子程序。在JavaScript中,函數實質上也是一種對象,是Function對象。函數一般會有參數與返回值(不是必須),在JavaScript中,函數的應用十分靈活,也有多種定義函數的方法。javascript
在JavaScript中,能夠經過函數語句來聲明和定義函數、能夠經過函數表達式來將建立函數,也可使用Function構造方法來建立函數對象。java
JavaScript中有一種特殊的語法來直接定義函數,示例以下:編程
//使用函數語句定義函數 function outputName(){ console.log("Jaki"); }
函數語句有這樣的結構:function name(param...){}。其中function爲函數語句的關鍵字,name爲自定義的函數名稱,小括號中定義函數的形參,大括號中能夠進行代碼的編寫。數組
若是僅僅對上面的代碼進行運行,你會發現程序並無執行任何行爲,函數必須在調用時纔會被執行,調用函數示例以下:函數
//使用函數語句定義函數 function outputName(){ console.log("Jaki"); } outputName();//將打印Jaki
上面的定義的函數是最簡單的函數形式,函數也能夠經過傳入參數的差別來作不一樣的功能,例如修改上面的函數,使其傳入姓名而且進行打印輸出:spa
//使用函數語句定義函數 function outputName(name){ console.log(name); } outputName("張三");//將打印張三
函數也能夠提供一個返回值,例如一個簡單的加法運算函數,以下:code
function add(a,b){ return a+b; } var res = add(3,4); console.log(res);//7
在JavaScript中,函數的返回值類型不須要特殊指定,直接使用return語句返回便可。須要注意,實際上任何函數都是有返回值的,若是函數體中沒有使用return語句顯式的進行返回,則默認會返回undefined。對象
JavaScript中函數的定義與使用不必定非要按照順序進行,實際上也能夠將函數的定義寫在使用以後(解釋器會在與處理階段解釋定義的函數),以下:遞歸
var res = add(3,4); function add(a,b){ return a+b; } console.log(res);//7
使用函數表達式來定義函數與函數語句的語法十分類似,示例代碼以下:ip
//使用函數表達式來定義函數 var addFunc = function(a,b){ return a+b; }; var res = addFunc(3,3); console.log(res);//6
這種方式定義的函數其實是建立了一個函數對象,以後將這個對象的引用賦值給了一個變量,經過變量開發者能夠訪問和調用函數。須要注意,函數表達式與函數語句的最大區別在於其能夠省略函數名,便可以定義匿名函數,可是這種方式定義的函數在函數定義以前是不可以被調用的,這也很好理解,JavaScript解釋器在預處理期間只是解析除了addFunc變量,可是並無對其表達式進行運算,這時函數並無被定義,例以下面的代碼將報錯:
var res = addFunc(3,3); //使用函數表達式來定義函數 var addFunc = function(a,b){ return a+b; };
其實函數語句與函數表達式定義的函數還有一點重大區別,函數語句定義後函數名其實是沒法修改的,而使用函數表達式定義的函數是將引用賦值給了變量,變量能夠從新賦值,也能夠將兩個變量賦值爲同一個函數對象的引用,示例以下:
//使用函數表達式來定義函數 var addFunc = function(a,b){ return a+b; }; //將addFunc的值賦值給另外一個變量 var addFunc2 = addFunc; //將addFunc變量修改成整型值 addFunc = 3; var res = addFunc2(3,3); console.log(res);//6
若是須要在函數內部調用函數自己,即須要定義遞歸函數時,函數表達式也能夠進行函數命名,示例以下:
//定義一個遞歸階乘函數 var mathFunc = function mathF(a){ var res = a; a--; if (a>0) { res *= mathFunc(a); } return res; }; var mathRes = mathFunc(5); console.log(mathRes);//120
須要注意,函數表達式定義的函數名只能做用於函數內部。
前面有提到,函數在JavaScript中實際上也是一種對象,所以可使用new關鍵字來進行函數對象的構造,示例以下:
//Function構造器 var myFunc = new Function("name","console.log(name)"); myFunc("Jaki");//Jaki
Function構造其的格式以下:Function(param,param...,funcbody)。其中參數個數不固定,最後一個參數爲建立的函數的函數體字符串,前面的參數所有都將做爲函數的形參傳入函數體內。
實際上,不管經過哪一種方式建立的函數,其實質上都是Function對象,Function對象中也有一些內置的屬性,其中最長用的爲arguments屬性。arguments屬性是實際傳入函數的參數數組,其length屬性爲函數所傳入的參數個數,也就是說,開發者在定義函數的時候實際上能夠不定義形參,在調用函數的時候直接進行實參的傳入,函數內部仍是能夠獲取到參數,JavaScript函數的對象特性使得其十分靈活,形參並不能決定函數的參數個數與類型,實參、函數體和返回值這些均可以在運行時決定!示例以下:
function testFunc(){ console.log(arguments.length); console.log(arguments); } /* 3 { '0': '1', '1': 2, '2': 3 } */ testFunc('1',2,3);
函數是功能完整的對象,實際上函數對象自己也有一個length屬性,這個屬性將獲取到函數預期形參的個數,便可以方便的獲取到函數預期須要傳入的參數的個數,例如:
function testFunc(){ console.log(arguments.length); console.log(arguments); } function textFunc2(name){ } console.log(testFunc.length); //0 console.log(textFunc2.length); //1
函數語句是定義函數的一種語法,而函數表達式實際上就是返回一個函數對象,所以函數表達式能夠直接進行調用,請看以下代碼:
var addFuncS = function(a,b){ console.log(a+b); }(1,2);//3
上面的代碼中的addFuncS已經再也不是一個函數對象的引用,而是數值3。在函數表達式後面能夠直接跟小括號傳參進行函數的調用,可是以下的寫法將會報錯:
function addFuncE(){ console.log("hello"); }();
在JavaScript中函數表達式十分容易被誤認爲是函數定義的語法,區分了上面兩種狀況,你會發現這是在編程過程當中十分危險,JavaScript中的函數語法有以下兩條規則:
1.當函數語法成爲表達式的一部分時,其會被轉換成爲函數表達式。
2.內嵌於非函數的其餘代碼塊中時,函數語法會被轉換成函數表達式。
例子以下:
//函數語法被轉換成函數表達式 //1.函數語法成爲表達式的一部分 (function f1(){console.log("f1")})(); //2.函數語法內嵌於非函數的代碼塊彙總 if (true) { (function f2(){ console.log("f2"); })(); }