一、調用
- <strong>方法調用模式</strong>
當一個函數被保存為對象的一個屬性時,我們稱它為一個方法。如果調用表達式包含一個提取屬性的動作,那么它就是被當做一個方法來調用。

方法可以使用this訪問自己所屬的對象,通過this可取得它們所屬對象的上下文的方法稱為公共方法。
-
<strong>函數調用模式</strong>
當一個函數并非一個對象的屬性時,那么它就是被當做一個函數來調用:
var sum = add(3, 4);//7
以此模式調用函數時,this被綁定到全局對象。
Paste_Image.png
這事語言設計的一個錯誤,錯誤后果就是方法不能利用內部函數來幫助它工作,因為內部函數的this被綁定了錯誤的值,所以不能共享該方法對對象的訪問權。
<b>解決方案:</b>
為該方法定義一個變量并給它賦值為this,那么內部函數就可以通過那個變量訪問到this:
Paste_Image.png - <strong>構造器調用模式</strong>
如果在一個函數前面帶上 new 來調用,那么背地里將會創(chuàng)建一個連接到該函數的prototype成員的新對象,同時 this 會被綁定到那個新對象上。
//創(chuàng)建一個名為Quo的構造器函數。它構造一個帶有status屬性的對象。
var Quo = function(string){
this.status = string
}
//給Quo的所有實例提供一個名為get_status的公共方法。
Quo.prototype.get_status = function(){
return this.status;
};
//構造一個Quo實例。
var myQuo = new Quo('confused');
myQuo.get_status()//'confused' - <strong>Apply調用模式</strong>
apply方法讓我們構建一個參數數組傳遞給調用函數。它也允許我們選擇this的值。apply方法接收兩個參數,第一個是要綁定給this的值,第二個就是一個參數數組。

二、擴充類型的功能
-
我們可以通過給Function.prototype 增加方法來使得該方法對所有函數可用
Paste_Image.png
通過給Function.prototype 增加一個method方法,我們下次給對象增加方法的時候就不必鍵入prototype這幾個字符,省掉了一點麻煩。
-
JavaScript沒有專門的整數類型,但有時候確實只需要提取數字中的整數部分。JavaScript本身提供的取整方法有些丑陋。我們可以通過Number.prototype增加一個integer方法來改善它。它會根據數字的正負來判斷是使用Math.ceiling還是Math.floor。
Paste_Image.png - PS:這里需要指出的是Javascript的原型繼承機制,可以形象的理解為Object是祖師爺爺,Function既當爹又當媽,剩下的Number,String,Array等都是兒女:
Number,String,Array => Function => Object

- 另外,基本類型的原型是公用結構,所以在類庫混用時務必小心。一個保險的做法是只在確定沒有該方法時才添加它。
//符合條件時才增加方法。
Function.prototype.method = function(name,func){
if(!this.prototype[name]){
this.prototype[name] = func;
}
return this;
}
三、閉包
-
我們通過調用一個函數的形式去初始化myObject,該函數會返回一個對象字面量。函數里定義一個value變量。該變量對increment和getValue方法總是可用的,但是函數的作用域使得它對其他的程序來說是不可見的。
Paste_Image.png
這個例子我們并沒有把一個函數賦值給myObject。我們是把調用該函數后返回的結果賦值給它。

當我們調用quo時,它返回包含get_status方法的一個新對象。該對象的一個引用保存在myQuo中。即使quo已經返回了,但get_status方法仍然享有訪問quo對象的status屬性的特權。get_status方法并不是訪問該參數的一個副本,它訪問的就是該參數本身。這是可能的,因為該函數可以訪問它被創(chuàng)建時所處的上下文環(huán)境,這被稱為<b>閉包</b>。
-
來看一個更有用的例子
Paste_Image.png
1.我們調用fade,把document.body作為參數傳遞給它,fade函數設置level為1.它定義一個step函數,接著調用setTimeout,并傳遞step函數和一個時間(100毫秒)給它。然后它返回,fade函數結束。
2.在大約100毫秒后,step函數被調用。它把fade函數的level變量轉換為16位字符。接著,它修改fade函數得到的節(jié)點的背景顏色。然后查看fade函數的level變量。如果背景色尚未變成白色,那么它增大fade函數的level變量,接著用setTimeout預定讓它自己再次運行。
3.step函數很快再次被調用。但這次,fade函數的level變量值變成2.fade函數在之前已經返回了,但只要fade的內部函數需要,它的變量就會持續(xù)保留。 - <b>從一個經典的錯誤說起</b>
構造六個div,當點擊一個div時,按照預期,應該打出相應div的值,但是它總是會顯示div的數量。因為事件處理器函數綁定了變量i本身,而不是函數在構造時的變量i的值,i始終無法被釋放。

避免在循環(huán)中創(chuàng)建函數,它可能只會帶來無謂的計算,還會引起混淆,正如上面那個經典的錯誤。我們可以先在循環(huán)外創(chuàng)建一個輔助函數,讓這個輔助函數再返回一個綁定了當前i值的函數,這樣就不會導致混淆了。改良后的例子,用正確的方式給一個數組中的節(jié)點設置事件處理程序

另一種解決辦法,這里我們用一個立即執(zhí)行函數給它包住,我們不再依賴i,而是用另外一個變量n把它保留下來。

四、記憶
-
函數可以將先前操作的結果記錄在某個對象里,從而避免無謂的重復運算。這種優(yōu)化被稱為<b>記憶</b>。JavaScript的對象和數組要實現這種優(yōu)化是非常方便的。
比如說,我們想要一個遞歸函數來計算Fibonacci數列。一個Fibonacci數列是之前兩個Fibonacci數字之和。最前面的兩個數字是0和1。
Paste_Image.png
但是這樣做了很多無謂的工作。fibonacci函數被調用了453次。如果我們讓該函數具備<b>記憶</b>功能,就能顯著地減少運算量。
我們在一個名為memo的數組里保存我們的存儲結果,存儲結果可以隱藏在閉包中。當函數被調用時,這個函數首先檢查結果是不是已經存在,如果存在,就立即返回這個結果。
Paste_Image.png
這個函數返回的結果相同,但是它只被調用了29次。 -
我們可以編寫一個函數來幫助我們構造帶<b>記憶</b>功能的函數。memoizer函數取得一個初始的memo數組和formula函數。它返回一個管理meno存儲和在需要時調用formula函數的recur函數。我們把這個recur函數和它的參數傳遞給formula函數:
Paste_Image.png
現在,我們可以使用memoizer函數來定義fibonacci函數,提供其初始的memo數組和formula函數:
Paste_Image.png
通過設計這種產生另一個函數的函數,極大地減少了我們的工作量。例如,要產生一個可以記憶的階乘函數,我們只需提供基本的階乘公式即可:
Paste_Image.png










