iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 21
5
Modern Web

重新認識 JavaScript系列 第 21

重新認識 JavaScript: Day 21 函式的 Combo 技: Cascade

本系列文章已重新編修,並在加入部分 ES6 新篇章後集結成書,有興趣的朋友可至天瓏書局選購,感謝大家支持。

購書連結 https://www.tenlong.com.tw/products/9789864344130

讓我們再次重新認識 JavaScript!


前一篇文章我們介紹過 this 在 JavaScript 的各種面貌,以及代表的意義。
那麼今天我們來看看 this 在實戰上搭配函式可以有什麼樣的應用。

JavaScript 的 function 允許沒有 return 回傳值,像這類沒有 return 的函式預設會回傳 undefined。 但如果我們把預設沒有 returnundefined 改成 return this 就可以有更多有趣且實用的變化。


先舉個例子,假設我們有個四則運算器:

var calNum = function(num){
  this.num = num;

  this.add = function(newNum) {
    this.num += newNum;
  };

  this.sub = function(newNum) {
    this.num -= newNum;
  };

  this.multi = function(newNum) {
    this.num *= newNum;
  };

  this.division = function(newNum){
    this.num /= newNum;
  };
};

然後我們透過 new 新增了一個 calNum 實體:

var a = new calNum(100);

console.log( a.num );       // 100

然後我們就可以個別針對不同的運算方式去呼叫對應的方法 (method):

a.add(100);
console.log( a.num );   // 200

a.sub(50);
console.log( a.num );   // 150

這裡你會發現我們先對 a.num 作加法,然後再對 a.num 做減法,分別呼叫了兩次 a 的方法屬性。

但是否有更簡便的做法呢? 這就是今天要介紹的主題: Cascade


Cascade

Cascade 也有人稱作 「Fluent Interface」,兩個指的都是同一件事。

那麼,什麼是「Cascade」 呢? 回到剛剛範例:

a.add(100);
console.log( a.num );   // 200

a.sub(50);
console.log( a.num );   // 150

像上面範例中,我們針對 a.num 的運算分別呼叫了兩次 a 的方法屬性。

這時你應該發現了,這兩次都是針對同一個物件屬性的運算更新,那麼我們可以改一下寫法:

var calNum = function(num){
  this.num = num;

  this.add = function(newNum) {
    this.num += newNum;
    return this;
  };

  this.sub = function(newNum) {
    this.num -= newNum;
    return this;
  };

  this.multi = function(newNum) {
    this.num *= newNum;
    return this;
  };

  this.division = function(newNum){
    this.num /= newNum;
    return this;
  };
};

將原本沒有 return 的四則運算方法,分別再把 this 回傳出來。

於是,神奇的事情發生了,我們可以在一行之內,把對 a.num 的運算搞定:

var a = new calNum(100);

a.add(100).sub(50);
console.log( a.num );   // 150

像這樣的風格就是「Cascade」或「Fluent Interface」,透過這樣方式可以做出方便、容易閱讀,而且一口氣把要做的事做完的事寫在一起。

像是大家都很熟悉的 jQuery 也是採用相同作法來做到「方法鍊」(method chaining):

$('div').addClass('is-active')
        .removeClass('is-hide')
        .text('Hello World!');

另外,像是 JavaScript 原本就有的 sort(),以及 ES6 之後新增的 filter()map() 以及 reduce() 也都有著類似的特性,差別在於回傳的是同個型別的物件,但內容是運算之後的結果:

var arr = [1, 2, 8, 0, 10, 51, 23, 32, 3, 7, 10, 9, 18, 5];

// 把 arr 陣列中奇數過濾出來,個別求出平方後,由小至大做排序
var num = arr.filter(function(a){ return a % 2 !== 0 })
             .map(function(a){ return a * a; })
             .sort(function(a, b){ return a - b; });
             
console.log(num);      // [1, 9, 25, 49, 81, 529, 2601]

像這樣的做法,可以讓程式碼看起來更簡潔,而且有著更好的可讀性,一眼就能看出處理的方法以及執行的順序。

但需要注意的是,並不是所有方法都適合這樣做,如果將原本有需要回傳的函式改寫的話,不僅會是個大工程,也本末倒置了。


上一篇
重新認識 JavaScript: Day 20 What's "THIS" in JavaScript (鐵人精華版)
下一篇
重新認識 JavaScript: Day 22 深入理解 JavaScript 物件屬性
系列文
重新認識 JavaScript37

尚未有邦友留言

立即登入留言