函數(shù)申明:
function functionName(arg0,arg1,arg2){
//函數(shù)體
}
函數(shù)表達式:
var functionName=function(arg0,arg1,arg2){
// 函數(shù)體
}; //注意 ;
functionName(arg0,arg1,arg2);
遞歸
function factorial(num){
if(num<=1){
return 1;
}else{
return num*factorial(num-1);
}
}
function factorial(num){
if(num<=1){
return 1;
}else{
return arguments.callee(num-1)*num;
}
}//這種方式在嚴(yán)格模式下會報錯
//最佳方法
var factorial = (function f(num){
if(num<=1){
return 1;
}else{
return num*f(num-1);
}
});
閉包
閉包是有權(quán)訪問另一個函數(shù)作用域中的變量函數(shù)沉噩。
function createComparisonFunction(propertyName){
return function(object1,object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1<value2){
return -1;
}else{
return 0;
}
};
}
即使函數(shù)中的匿名函數(shù)被返回了昆禽,而且在其他地方被調(diào)用了择卦,但它仍然可以訪問變量propertyName。這是因為內(nèi)部函數(shù)的作用域鏈中包含了createComparisonFunction()的作用域.
作用域鏈
- 當(dāng)某個函數(shù)第一次被調(diào)用時祈噪,會創(chuàng)建一個 執(zhí)行環(huán)境 及相應(yīng)的 作用域鏈尚辑,并把作用域鏈賦值給一個特殊的內(nèi)部屬性(執(zhí)行環(huán)境中的[[Scopr]])。然后遂填,使用this澈蝙、arguments和其他命名參數(shù)的值來初始化函數(shù)的 活動對象。外部函數(shù)的活動對象始終處于第二位礁击,外部函數(shù)的外部函數(shù)的活動對象處于第三位.....
function compare(value1, value2){
if(value1 < value2){
return -1;
} else{
return 1;
}
}
執(zhí)行環(huán)境及相應(yīng)的作用域鏈
后臺的每個 執(zhí)行環(huán)境 都有一個表示變量的對象—— 變量對象逗载。全局環(huán)境的變量對象始終存在厉斟,而想compare()函數(shù)這樣的局部環(huán)境的變量對象,只有在函數(shù)執(zhí)行的過程中存在(活動對象)擦秽。
在創(chuàng)建compare()函數(shù)時,會創(chuàng)建一個預(yù)先包含全局變量對象的作用域鏈缩搅,這個作用域鏈保存在內(nèi)部的[[Scope]]屬性中。當(dāng)調(diào)用compare()時究飞,會為函數(shù)創(chuàng)建一個執(zhí)行環(huán)境堂鲤,然后通過復(fù)制函數(shù)的[[Scope]]屬性中的對象構(gòu)建執(zhí)行環(huán)境的作用域鏈。此后,又有一個活動對象(變量對象)被創(chuàng)建并被推入執(zhí)行環(huán)境作用域鏈的前端丝蹭。
作用域鏈的前端奔穿,始終都是當(dāng)前執(zhí)行的代碼所在環(huán)境的變量對象。如果這個環(huán)境是函數(shù)贱田,則將其活動對象作為變量對象。 (活動對象就是作用域鏈上正在被執(zhí)行和引用的變量對象)
function createComparisonFunction(propertyName){
return function(object1,object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1<value2){
return -1;
}else{
return 0;
}
};
}
在匿名函數(shù)從createComparisonFunction()中被返回后,它的作用域鏈被初始化為包含createComparisonFunction()函數(shù)的 活動對象 和 全局變量對象耗拓。這樣,匿名函數(shù)就可以訪問在createComparisonFunction()中定義的所有變量樟插。當(dāng)createComparisonFunction()函數(shù)返回后竿刁,其執(zhí)行環(huán)境的作用域鏈被銷毀,但它的活動對象仍然會留在內(nèi)存中鸵熟,直到匿名函數(shù)被銷毀后负甸,createComparisonFunction()的活動對象才會被銷毀齿桃。
閉包與變量
閉包只能取得包含函數(shù)中任何變量的最后一個值煮盼。
function createFunction(){
var result = new Array();
for(var i=0; i<10; i++){
result[i] = function(){
return i;
}
}
return result;
}
這個函數(shù)會返回一個函數(shù)數(shù)組僵控,每個函數(shù)都返回10。因為每個函數(shù)的作用域鏈中都保存著createFuntion函數(shù)的活動對象报破,并返回了createFunction中變量i的值充易,由于經(jīng)過for循環(huán)i的值變?yōu)榱?0,所以result中每個函數(shù)都只會返回10盹靴。
通過創(chuàng)建另一個匿名函數(shù)強制讓閉包的行為符合預(yù)期:
function createFunctions()
{
var result = new Array();
for(var i=0;i<10;i++)
{
result[i] = function(num)
{
return function()
{
return num;
}
}(i);
}
return result;
}
由于函數(shù)參數(shù)傳遞是按值傳遞的稿静,所以就會將變量i的當(dāng)前值復(fù)制給參數(shù)num,而在這個匿名函數(shù)內(nèi)部改备,又創(chuàng)建并返回了一個訪問num的閉包。這樣一來悬钳,result數(shù)組中的每函數(shù)都有自己num變量的一個副本,因此就可以返回各自不同的數(shù)值了毙驯。
this對象
var name = "The Window";
var object = {
name : "My Object",
getNameFunc: function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); // The Window
//object.getNameFunc()返回的是一個匿名函數(shù)灾测,想要調(diào)用該匿名函數(shù)還需要加一個()
出現(xiàn)這樣的現(xiàn)象的原因分析(自己理解):
在創(chuàng)建匿名函數(shù)時媳搪,會創(chuàng)建一個預(yù)先包含全局變量對象的作用域鏈(包括this,此時this為GLobal對象)秦爆,這個作用域鏈被保存在內(nèi)部的[[Scope]]屬性中。當(dāng)調(diào)用匿名函數(shù)時爸吮,會為函數(shù)創(chuàng)建一個執(zhí)行環(huán)境,然后通過復(fù)制函數(shù)的[[Scope]]屬性中的對象構(gòu)建起執(zhí)行環(huán)境的作用域鏈锰霜。因此該例中桐早,匿名函數(shù)中的this仍然為Global對象。
在javascript中友存,函數(shù)的調(diào)用一共有4種方式:
- Function Invocation Pattern
諸如foo()
的調(diào)用形式被稱為Function Invocation Pattern陶衅,是函數(shù)最直接的使用形式,注意這里的foo是作為單獨的變量出現(xiàn)膨俐,而不是屬性奕巍。
在這種模式下儒士,foo函數(shù)體中的this永遠(yuǎn)為Global對象,在瀏覽器中就是window對象诅福。 - Method Invocation Pattern
諸如foo.bar()
的調(diào)用形式被稱為Method Invocation Pattern拖叙,注意其特點是被調(diào)用的函數(shù)作為一個對象的屬性出現(xiàn),必然會有“.”或者“[]”這樣的關(guān)鍵符號咖气。
在這種模式下挖滤,bar函數(shù)體中的this永遠(yuǎn)為“.”或“[”前的那個對象,如上例中就一定是foo對象伶唯。 - Constructor Pattern
new foo()
這種形式的調(diào)用被稱為Constructor Pattern惧盹,其關(guān)鍵字new
就很能說明問題瞪讼,非常容易識別粹断。
在這種模式下,foo函數(shù)內(nèi)部的this永遠(yuǎn)是new foo()返回的對象背亥。 - Apply Pattern
foo.call(this悬赏,Object)
和foo.apply(this,Object)
的形式被稱為Apply Pattern盾戴,使用了內(nèi)置的call
和apply
函數(shù)兵多。
在這種模式下,call
和apply
的第一個參數(shù)就是foo函數(shù)體內(nèi)的this衅斩,如果thisObject是null
或undefined
怠褐,那么會變成Global對象。
// 把外部作用域中的this對象保存在一個閉包能夠訪問到的變量里奠涌,就可以讓閉包訪問該對象了
var name = "The Window";
var object = {
name : "My Object",
getNameFunc: function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); // The Object
模仿塊級作用域
(function(){
//這里是塊級作用域
}) ();
以上代碼定義并立即調(diào)用了一個匿名函數(shù)磷杏。將函數(shù)申明包含在一對圓括號中极祸,表示它實際上是一個 函數(shù)表達式 。而緊隨其后的另一對圓括號會立即調(diào)用這個函數(shù)遥金。
私有變量
- JavaScript中沒有私有成員的概念汰规;所有的對象屬性都是公有的。但是有私有變量的概念溜哮。私有變量包括函數(shù)的參數(shù)、局部變量和在函數(shù)內(nèi)部定義的其他函數(shù)餐茵。
- 如果在函數(shù)內(nèi)部創(chuàng)建一個閉包,那么閉包通過自己的作用域鏈也可以訪問這些變量锣笨,利用這點道批,可以創(chuàng)建用于訪問私有變量的公有方法。
/* demo01 */
function MyObject(){
var privateVariable = 10;
function privateFunction(){
return false;
}
this.publicMethod = function(){
privateVariable++;
return privateFunction();
};
}
var object = new MyObject();
object.publicMethod(); //false
如果需要構(gòu)建多個實例椭岩,則需為每個實例創(chuàng)建同樣的方法
靜態(tài)私有變量
(function(){
var privateVariable = 10;
function privateFUncion(){
return false;
}
MyObject = function(){
};
MyObject.prototype.publicMethod = function(){
privateVariable++;
return privateFunction();
}
})
// 使用
var object = new MyObject();
注意 :定義構(gòu)造函數(shù)時璃赡,沒有使用函數(shù)生命,而是使用了函數(shù)表達式碉考。函數(shù)聲明只能創(chuàng)建局部函數(shù)。出于同樣的原因锌仅,在聲明MyObject時也沒有使用var關(guān)鍵字良蒸。** 記住 ** : ** 初始話未經(jīng)聲明的變量伍玖,總是會創(chuàng)建一個全局變量 ** 窍箍。因此MyObject就成為一個全局變量,能夠在私有作用域之外被訪問椰棘。 ** 靜態(tài)私有變量 ** privateVariable時被所有實例共享的邪狞,它可以任何實例修改(通過publicMethod方法)
模塊模式
模塊模式通過為單例添加私有變量和特權(quán)方法能夠使其得到增強
var singleton = function(){
var privateVariable = 10;
function privateFunction(){
return false;
}
// 返回一個對象
return {
publicProperty: true;
publicMethod: function(){
privateVariable++;
return privateFunction();
}
};
}();
singleton.publicProperty;
singleton.publicMethod();
這個模塊模式使用了一個返回對象的匿名函數(shù)。
增強的模塊模式
返回特定類型的對象
var singleton = function(){
var privateVariable = 10;
function privateFunction(){
return false;
}
// 可以返回特定類型的對象
var object = new CustomType();
object.publicProperty = true;
object.publicMethod = function(){
privateVariable++;
return privateFunction();
}
}();
singleton.publicProperty;
singleton.publicMethod();