函數(shù)表達(dá)式
-
函數(shù)聲明 sample:
function functionName(arg0,agr1){ //contents }
函數(shù)聲明會把函數(shù)聲明提前。函數(shù)聲明不要寫在if for循環(huán)等代碼塊中,如果一定要
在if語句或者循環(huán)語句中定義函數(shù)可以用函數(shù)表達(dá)式的辦法。 -
第二種方法:函數(shù)表達(dá)式 sample:
var functionName = function(agr0,arg1,arg2){ //contents };
函數(shù)表達(dá)式?jīng)]有聲明提前的效果,所以必須先賦值,再使用。像變量一樣。
-
遞歸 建議使用命名函數(shù)表達(dá)式
建議使用下面的例子遞歸 sample:var factorial = function f(num){ if (num <= 1){ return 1; } else { return num * f(num - 1); } } factorial(4);//24
-
閉包 閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)。創(chuàng)建閉包的常見方式,就是在
一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)。
sample:function createComparisonFunction(propertyName){ return function(obj1,obj2){ var val1 = obj1[propertyName]; var val2 = obj2[propertyName]; if (val1 < val2){ return -1; } else if (val1 > val2){ return 1; } else { return 0; } }; }
上面這個(gè)例子中內(nèi)部匿名函數(shù)可以訪問外部的propertyName,是因?yàn)?br> 內(nèi)部函數(shù)的作用域鏈中包含createComparisonFunction()的作用域。
再舉個(gè)例子
sample:function compare(val1,val2){ if(val1>val2){ return 1; } else if ( val1 > val2 ){ return -1; } else { return 0; } } var result = compare(5,10);
作用域鏈如下所示:
作用域鏈.jpg
后臺的每個(gè)執(zhí)行環(huán)境都有一個(gè)用來表示變量的對象---變量對象。
而全局的變量對象始終存在,而函數(shù)的局部環(huán)境的變量對象,只有在
函數(shù)的執(zhí)行時(shí)存在。在創(chuàng)建compare()函數(shù)時(shí),會創(chuàng)建一個(gè)預(yù)先包含
全局變量對象的作用域鏈。這個(gè)作用域鏈保存在內(nèi)部的[[Scope]]
屬性中。當(dāng)調(diào)用compare()函數(shù)時(shí),會為函數(shù)創(chuàng)建一個(gè)執(zhí)行環(huán)境,然后通過
復(fù)制函數(shù)[[Scope]]屬性中的對象構(gòu)建起執(zhí)行環(huán)境的作用域鏈。此后又有
一個(gè)活動對象被創(chuàng)建并推入執(zhí)行環(huán)境作用域鏈的前面。對于這個(gè)例子來說
,其作用域鏈中包含兩個(gè)變量對象:本地活動對象和全局變量對象 。
當(dāng)在函數(shù)中訪問一個(gè)變量時(shí),就會從作用域鏈中搜索具有相應(yīng)名字的變量,一般來說
當(dāng)函數(shù)執(zhí)行完畢后,局部活動對象就會被銷毀,內(nèi)存中僅保存娟娟作用域(全局執(zhí)行環(huán)境的變量對象)
但閉包就不一樣了。
內(nèi)部函數(shù)會把外部函數(shù)的活動對象添加到它的作用域鏈中,因此,
在createComparisonFunction()函數(shù)內(nèi)部定義的匿名函數(shù)的作用域鏈中,會包含外部
函數(shù)createComparsionFunction()的活動對象
var compare = 函數(shù)createComparsionFunction('name');
var result = compare({ name: "Tom" },{ name: "Jerry" });
在匿名函數(shù)從createComparisonFunction()中被返回后,它的作用域鏈被初始化為
包含createComparsionFunction()函數(shù)的活動對象和全局變量對象。這樣匿名函數(shù)就可以訪問在
createComparisonFunction()中定義的所有變量了。而且更重要的是,外部函數(shù)在執(zhí)行完畢后,
其活動對象也不會被銷毀,因?yàn)閮?nèi)部匿名函數(shù)仍然在引用這個(gè)活動對象。直到匿名函數(shù)被銷毀,外部函數(shù)
的活動對象才會銷毀。
所以閉包會占用內(nèi)存,要合理使用閉包。
function createFunctions(){
var result = new Array();
for (var x=0; x < 10; x++){
result[x] = function(){
return x*3;
};
}
return result;
}
var z = createFunctions();
z[2]();//30
z[7]();//30
原本希望批量得到一批函數(shù),這些函數(shù)返回三倍的輸入值。但實(shí)際上所有函數(shù)返回的
都是30,也就是最后的x的值10*3。因?yàn)楫?dāng)調(diào)用返回的那個(gè)內(nèi)部匿名函數(shù)的時(shí)候,x的值是循環(huán)
之后的10。
可以改成以下
function createFunctions(){
var result = new Array();
for ( var x = 0;x < 10 ;x++ ){
result[x] = function(num){
return function(){
return num;
};
}(x);
}
return result;
}
之所以能成功,是因?yàn)樽罾锩娴哪涿瘮?shù)搜索num時(shí),會找到他外部的函數(shù),而它
外部函數(shù)的num是通過值傳遞進(jìn)去的,每循環(huán)一次num被賦值不同的值。
- 模仿塊級作用域
javascript沒有塊級作用域(ES6有了)所以在for循環(huán)外面可以訪問變量i
可以使用立即調(diào)用匿名函數(shù)的方法模擬塊級作用域從而防止全局變量污染。
sample:(function(){ //這里是塊級作用域 })();
function outputNumbers(count){ (function () { for (var i=0 ; i< count;i++){ alert(i); } })(); alert i;//報(bào)錯(cuò),未定義的變量。 }