1.遞歸函數(shù)是在一個函數(shù)通過調(diào)用自身的情況下構(gòu)成的。
~~~
function factorial(num){
if (num<=1){
return 1;
} else {
return num*arguments.callee(num-1);
}
}
~~~
~~~
var factorial = (function f(num){
if (num<=1){
return 1;
} else {
return num*f(num-1);
}
});
~~~
以上代碼創(chuàng)建了一個名為f()的**命名函數(shù)表達(dá)式**,然后將它賦給了另一個變量,函數(shù)的名字f仍然有效,所以遞歸調(diào)用照樣能正確完成。這種方式在嚴(yán)格模式和非嚴(yán)格模式下都行得通。
2.閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的**函數(shù)**。
3.創(chuàng)建閉包的常見方式,就是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù)。
~~~
function createComparisionFunction(propertyName){
return function (object1, object2) {
var value1 = object1[propertyName];
var value2 = onbect2[propertyName];
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
};
}
~~~
**當(dāng)createComparisionFunction()函數(shù)返回后,其執(zhí)行環(huán)境的作用域會被銷毀,但他的活動對象仍然會留在內(nèi)存中;直到匿名函數(shù)被銷毀后,createComparisionFunction()的活動對象才會被銷毀。**
~~~
//創(chuàng)建函數(shù)
var compareNames = createComparisionFunction('name');
//調(diào)用函數(shù)
var result = compareNames({name:'Nicolas'},{name:'Greg});
//解除對匿名函數(shù)的引用(以便釋放內(nèi)存)
compareNames = null;
~~~
4.匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此其this對象通常指向window。但有時候由于編寫閉包的方式不同,這一點(diǎn)可能不回那么明顯。
~~~
var name = 'The window';
var object = {
name: 'My Object',
getNameFunc: function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //'The window'(在非嚴(yán)格模式下)
~~~
5.對已經(jīng)沒有用處的、閉包外部函數(shù)(保存著對象)的變量,應(yīng)該將其設(shè)置為null以避免內(nèi)存泄露。
~~~
function assignHandler(){
var element = document.getElementById('someElement');
var id = element.id;
element.onclick = function(){
alert(id);
};
element = null;
}
~~~
6.用作塊級作用域(通常稱為私有作用域)的匿名函數(shù)語法如下:
~~~
(function(){
//這里是塊級作用域
})();
~~~
無論什么時候,只要臨時需要一些變量,就可以使用私有作用域。這種技術(shù)經(jīng)常在全局作用域中被用在函數(shù)外部,從而限制向全局作用域中添加過多的變量和函數(shù)。這種做法可以減少閉包占用的內(nèi)存問題,因?yàn)闆]有指向匿名函數(shù)的引用。只要函數(shù)執(zhí)行完畢,就可以立即銷毀其作用域鏈了。
7.私有變量包括函數(shù)的參數(shù)、局部變量和在函數(shù)內(nèi)部定義的其他函數(shù)。
8.有權(quán)訪問私有變量和私有函數(shù)的公有方法稱為**特權(quán)方法**。有兩種在對象上創(chuàng)建特權(quán)方法的方式。第一種是在構(gòu)造函數(shù)中定義特權(quán)方法。
~~~
function MyObject(){
//私有變量和私有函數(shù)
var privateVariable = 10;
function privateFunction(){
return false;
}
//特權(quán)方法
this.publicMethod = function(){
privateVariable++;
return privateFunction();
};
}
~~~
利用私有和特權(quán)成員,可以隱藏那些不應(yīng)該被直接修改的數(shù)據(jù):
~~~
function Person(name){
this.getName = function(){
return name;
};
this.setName = function(value){
name = value;
};
}
~~~
以上代碼的構(gòu)造函數(shù)定義了兩個特權(quán)方法:getName()和setName()。這兩個方法都可以在構(gòu)造函數(shù)外部使用,而且都有權(quán)訪問私有變量name。但在Person構(gòu)造函數(shù)外部,沒有任何辦法訪問name。不過,在函數(shù)中定義特權(quán)方法也有一個缺點(diǎn),那就是必須使用構(gòu)造函數(shù)模式來達(dá)到這個目的。(方法無法復(fù)用)
9.通過在私有作用域中定義私有變量或函數(shù),同樣也可以創(chuàng)造特權(quán)方法,即**靜態(tài)私有變量**。
~~~
(function(){
//私有變量和私有函數(shù)
var privateVariable = 10;
function privateFunction(){
return false;
}
//構(gòu)造函數(shù)
MyObject = function(){};
//公有、特權(quán)方法
MyObject.prototype.publicMethod = function(){
privateVariable++;
return privateFunction();
};
})();
~~~
這個模式與在構(gòu)造函數(shù)中定義特權(quán)方法的主要區(qū)別,就在于私有變量和函數(shù)是由實(shí)例共享的。由于特權(quán)方法是在原型上定義的,因此所有實(shí)例都是用同一個函數(shù)。而這個特權(quán)方法,作為一個閉包,總是保存著對包含作用域的引用。以這種方式創(chuàng)建靜態(tài)私有變量會因?yàn)槭褂迷投黾哟a復(fù)用,但每個實(shí)例都沒有自己的私有變量了。
10.前面的模式是用于為自定義類型創(chuàng)建私有變量和特權(quán)方法的。而**模塊模式**則是為單例創(chuàng)建私有變量和特權(quán)方法。所謂單例,指的就是只有一個實(shí)例的對象。模塊模式通過為單例添加私有變量和特權(quán)方法能夠使其得到增強(qiáng),其語法形式如下:
~~~
var singleton = function(){
//私有變量和私有函數(shù)
var privateVariable = 10;
function privateFunction(){
return false;
}
//特權(quán)/公有方法和屬性
return {
publiceProperty: true,
publicMethod: function(){
privateVariable++;
return privateFunction();
}
};
}();
~~~
由于這個返回的對象是在匿名函數(shù)內(nèi)部定義的,因此它的公有方法有權(quán)訪問私有變量和函數(shù)。從本質(zhì)上講,這個對象字面量定義的是單例的公共接口。這種模式在需要對單例進(jìn)行某些初始化,同時又需要維護(hù)其私有變量時是非常有用的。例如:
~~~
var application = function(){
//私有變量和函數(shù)
var conponents = new Array();
//初始化
components.push(new BaseComponent());
//公共
return {
getComponentCount: function(){
return components.length;
},
registgerComponent: function(component){
if (typeof component == 'object'){
components.push(component);
}
};
}();
~~~
在web應(yīng)用程序中,經(jīng)常需要使用一個單例來管理應(yīng)用程序級的信息。這個簡單的例子創(chuàng)建了一個用于管理組件的application對象。在創(chuàng)建這個對象的過程中,首先聲明了一個私有的components數(shù)組,并向這個數(shù)組添加了一個BaseComponent的新實(shí)例。而返回對象的getComponentCount()和registerComponent()方法,都是有權(quán)訪問數(shù)組components的特權(quán)方法。前者只是返回已注冊的組件數(shù)目,后者用于注冊新組件。
簡而言之,如果必須創(chuàng)建一個對象并以某些數(shù)據(jù)對其進(jìn)行初始化,同時還要公開一些能夠訪問這些私有數(shù)據(jù)的方法,那么就可以使用模塊模式。
11.**增強(qiáng)的模塊模式**適合那些單例必須是某種類型的實(shí)例,同時還必須添加某些屬性和(或)方法對其加以增強(qiáng)的情況。改寫前面的例子:
~~~
var application = function(){
//私有變量和函數(shù)
var conponents = new Array();
//初始化
components.push(new BaseComponent());
//創(chuàng)建application的一個局部副本
var app = new BaseComponent();
//公共接口
app.getComponentCount = function(){
return components.length;
};
app.registgerComponent = function(component){
if (typeof component == 'object'){
components.push(component);
}
};
return app;
}();
~~~
- 第一章 JavaScript簡介
- 第二章 在HTML中使用JavaScript
- 第三章 基本概念
- 第四章 變量、作用域和內(nèi)存問題
- 第五章 引用類型
- 第六章 面向?qū)ο蟮某绦蛟O(shè)計
- 第七章 函數(shù)表達(dá)式
- 第八章 BOM
- 第九章 客戶端檢測
- 第十章 DOM
- 第十一章 DOM擴(kuò)展
- 第十二章 DOM2和DOM3
- 第十三章 事件
- 第十四章 表單腳本
- 第十六章 HTML5腳本程序
- 第十七章 錯誤處理與調(diào)試
- 第二十章 JSON
- 第二十一章 AJAX和Comet
- 第二十二章 高級技巧
- 第二十三章 離線應(yīng)用與客戶端存儲
- 第二十四章 最佳實(shí)踐
- 第二十五章 新興的API
