本系列文章已重新編修,並在加入部分 ES6 新篇章後集結成書,有興趣的朋友可至天瓏書局選購,感謝大家支持。
購書連結 https://www.tenlong.com.tw/products/9789864344130
讓我們再次重新認識 JavaScript!
前一篇文章我們介紹過 this
在 JavaScript 的各種面貌,以及代表的意義。
那麼今天我們來看看 this
在實戰上搭配函式可以有什麼樣的應用。
JavaScript 的 function 允許沒有 return
回傳值,像這類沒有 return
的函式預設會回傳 undefined
。 但如果我們把預設沒有 return
的 undefined
改成 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 也有人稱作 「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]
像這樣的做法,可以讓程式碼看起來更簡潔,而且有著更好的可讀性,一眼就能看出處理的方法以及執行的順序。
但需要注意的是,並不是所有方法都適合這樣做,如果將原本有需要回傳的函式改寫的話,不僅會是個大工程,也本末倒置了。