深刻理解JavaScript函數

深刻理解JavaScript函數

1、引言

    從功能上理解,函數是一組能夠隨時運行的語句,是一段代碼塊,也是所謂的子程序。在JavaScript中,函數實質上也是一種對象,是Function對象。函數一般會有參數與返回值(不是必須),在JavaScript中,函數的應用十分靈活,也有多種定義函數的方法。javascript

2、幾種定義函數的方式

    在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

2.使用函數表達式來定義函數

    使用函數表達式來定義函數與函數語句的語法十分類似,示例代碼以下: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

須要注意,函數表達式定義的函數名只能做用於函數內部。

3.使用Function構造函數

    前面有提到,函數在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

3、理解函數語句與函數表達式

    函數語句是定義函數的一種語法,而函數表達式實際上就是返回一個函數對象,所以函數表達式能夠直接進行調用,請看以下代碼:

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");
	})();
}
相關文章
相關標籤/搜索