iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 24
0
自我挑戰組

寇丁人妻的前端書蟲日誌系列 第 24

Day24:JavaScript 設計模式 優良部份 Chapter04 函式 筆記精要

  • 函式是基礎模組的單位。
  • 程式設計的精義就是把一組需求分解成一組函式和資料結構。

函式物件

  • 函式物件連接到Function.prototype
  • 韓式隱藏兩個特性。
    • context。
    • 實作函式行為的程式碼。
  • 函式建立一個 prototype 特性。
    • 該特性具有 constructor 特性。
    • constructor 特性是一個函式。
  • 函式是物件,能被儲存在變數、物件、陣列中。
  • 函式可以被當引數傳給另一個函式,也能被另一個函式回傳。
  • 函式也能有方法。

函式實字

  • 函式實字有四個部分:
    • 保留字 function
    • 函式名稱,如果沒有名稱就為匿名函式
    • 參數的集合,以逗號區隔
    • 函式本體,任何運算式或函式皆可出現。
  • 內層的函式可以取用參數及變數,也可享用外層的參數及變數,函式實字建立物件包含對外的聯繫,稱為閉包。
var add = function(a, b){
    return a + b;
}

呼叫

  • 暫緩現有函式的執行,把控制權和參數傳給新呼叫的函式。
  • 每個函式均接受兩個額外參數:this 與 arsument
    • this:值由呼叫模式決定。
    • 呼叫模式:方法呼叫、建構式呼叫、函式呼叫、apply 呼叫。
  • 函式呼叫的運算子為一對小括號,皆在任何函式後方。
  • 小括號包含一到多段運算式,以逗號區隔,運個運算產生引數值。
  • 引數值被指定給函式參數。
  • 引數和函式參數數量不對等,不會產生錯誤。
  • 引數太多,多於引數會被忽略。
  • 引數太少,則以 undefined 取得缺少的值。
  • 引數不會檢查型別,任何的型別都可以傳給參數。

方法呼叫模式

  • 函式儲存成物件特性,稱之為方法。
  • 呼叫方法,this 與物件相繫。
  • 呼叫的運算式包含精確式,則呼叫時視同方法。
  • 方法可使用 this 存取物件,能從物件中擷取值、調整物件。
var myobj = {
    value: 0,
    increment: function (inc) {
        this.value += typeof inc === 'number' ? inc : 1;
        // 引數不是數值,則使用預設 1。
    }
};


myObject.increment( );
console.log(myObject.value); //1

myObject.increment(2);
console.log(myObject.value); //3

函式呼叫模式

  • 函式不是物件模式,只是像一般函式被呼叫。
  • 使用此種模式,this 會繫結全域變數,這是設計上的錯誤。
    • 呼叫內層函式,this 應該要繫結外層函式的 this。
    • 解決方法:定義一個變數,並指定為 this,習慣命名為 that。
myObject.double = function ( ) {
    var that = this; 
    
    var helper = function ( ) {
        that.value = add(that.value, that.value)
    };
}


myObject.double( );
document.writeln(myObject.getValue);

建構式呼叫模式

  • JavaScript 是一種原型繼承語言,不用類別,直接繼承其他物件的特性。
  • 函式呼叫時加上new,建立的新物件將附有對函式的 prototype 有繫結,且 this 與新物件結合。
  • 與字首new合用的函式稱為建構式,未附上會有編譯錯誤的狀況。
  • 習慣上,建構函式的名稱首字應該為大寫。

apply 呼叫模式

  • apply 方法可以建構一個引數陣列。
  • 第一個參數為繫結 this 的值,第二個則是參數的陣列。
var array = [3, 4];
var sum = add.apply(null, array);

var statusObject = {
    status: 'A-OK'
};

var status = Quo.prototype.get_status.apply(statusObject);

arguments 陣列

  • 呼叫時獲取的額外參數即為 arguments 陣列。
  • 函式可接受不特定數量的參數。
  • arguments 並非真正的陣列,為具有長度的類陣列。
var sum = function ( ){
    var i, sum = 0;
    for (i = 0 ; i < arguments.length; i += 1 ){
        sum += arguments[i];
    }
    return sum;
};

回傳

  • 呼叫函式,在遇到}結尾符號結束呼叫。
  • 執行 return,函式立刻回傳,且不會執行後面敘述。
  • 函數回傳一定會傳值,如果沒有指定就會回傳 undefind。
  • 如果是建構式呼叫,return 值不是物件,就改為傳 this。

例外狀況

  • 當某些狀況干擾程式流向,JavaScript 有一些機制處理那些狀況。
  • throw 敘述負責中斷函式執行:
    • 需要拿到一個期待物件。
    • 物件包含 name 和 message,也可以加入其他特性:
  • 範例:
var add = function (a, b) {
    if (typeof a !== 'number' || typeof b !== 'number') {
        throw {
            name: 'TypeError',
            message: 'add need numbers'
        }
        return a + b;
    }
}
  • 如果 try 有例外事件,那程式會跑 catch 的部分。
var try_it = function ( ) {
    try {
        add ('seven');
    } catch (e) {
        document.writeln(e.name + ' ' + e.message);
    }
}

擴充型別

  • JavaScript 允許基本型別擴充。
  • prototype 新增方法之後,呼叫方法就可以不用再鍵入「prototype」。
  • 擴充基本型別,可以改良語言的表達性,即使方法出現之前,被建立的值也會被擴充。
  • for-in 和原型的互動很差,可使用 hasOwnProperty 遮擋被繼承的特性。

遞迴

  • 遞迴是個值或間接呼叫自己的函式。
  • 遞迴會自我呼叫以解決子問題。
  • 河內之塔是有名的數學謎題。(初階可以參考費波納齊數列)
  • 有些語言提供尾遞迴最佳化的,就是函式回傳自我呼叫的結果,以迴圈取代呼叫,但 JavaScript 沒有提供,遞迴過深會讓堆疊疲憊。

範圍

  • 範圍控制變數與參數的可見性及生命週期。
    • 減少命名衝突
    • 自動記憶體管理
  • JavaScript 沒有區塊範圍,但有區塊語法。
  • JavaScript 具有函式範圍,意思是定義在函式內的變數及參數,脫離函式就不可見。
  • 因為 JavaScript 沒有區塊,所以使用變數時再宣告變數,這樣並不好。

closure

  • 內層函式能取用外層函式的參數和變數(除了 this 和 arguments),而不是變數的拷貝。

  • 範例:

    • 呼叫一個回傳物件實字的函式。
    • 把呼叫函式的結果回傳給 myObject。
    • 函式回傳兩個方法的物件,兩個方法皆可取用 value。
var myObject = function ( ){
    var value = 0;
    
    return {
        increment: function (inc) {
            value += typeof inc === 'number' ? inc : 1;
        },
        getValue: function ( ) {
            return value;
        }
    }
}( );

回呼

網路上有同步請求,會使得用戶處於凍結狀態,較佳的方式是製作非同步請求,用戶才不會被阻塞。

模組

  • 可以使用函式搭配閉包製作模組。
  • 模組是個函式或物件,用於呈現介面,隱藏他的狀態及實作。
  • 使用韓式製作模組,幾乎可以全面消除全域變數。
  • 模組利用函式範圍與閉包繫結私有關係。
  • 常用的模組模式,一個「定義 private 變數與函式」的函式,他透過閉包取用私有變數與函式的特許值。
  • 使用模組模式,可以削減全域變數的使用。

Cascade

  • 鏈狀為單一敘述,連續呼叫同一物件中的許多方法。

curry

  • curry 結合函式與引數,而產生新的函式。
  • curry 建立一個對 curry 保存原始函式的結果、呼叫 curry 時的所有引數的呼叫。
  • curry 為單一輸入、單一輸出,目的是為了解決多參數輸入,所以必須拆分函式。

Memoization

  • 大量重複計算,快取先前的結果。
  • 函式能利用物件以記憶前一次的操作,因而避免不必要的工作。

資料來源:《JavaScript 優良部份》 Douglas Crockford 著 歐萊禮
筆記純屬推廣及分享,如有侵權,請告知。
Please advise to remove immediately if any infringement caused.


上一篇
Day23:JavaScript 設計模式 優良部份 Chapter03 物件 筆記精要
下一篇
Day25:JavaScript 設計模式 優良部份 Chapter05 繼承 筆記精要
系列文
寇丁人妻的前端書蟲日誌30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言