JavaScript 設計模式與開發實踐讀書筆記

RedaVNUM 8年前發布 | 20K 次閱讀 設計模式 JavaScript開發 JavaScript

JavaScript 設計模式與開發實踐讀書筆記

最近利用碎片時間在 Kindle 上面閱讀《JavaScript 設計模式與開發實踐讀書》這本書,剛開始閱讀前兩章內容,和大家分享下我覺得可以在項目中用的上的一些筆記。

我的 github 項目會不定時更新,有需要的同學可以移步到我的 github 中去查看源碼: https://github.com/lichenbuliren/design-mode-notes

1、currying 函數柯里化

currying 又稱 部分求值 。一個 currying 的函數首先會接受一些參數,接受了這些參數之后,該函數并不會立即求值,而是繼續返回另外一個函數,將剛才傳入的參數在函數形成的閉包中被保存起來。待到函數被真正需要求值的時候,之前傳入的所有參數都會被一次性的用于求值。

假設我們需要編寫一個計算每個月開銷的函數,在每天結束之前,我們要記錄每天花掉了多少錢。

通用 currying 函數:

var currying = function(fn) {
  var args = [];

return function() { if (arguments.length === 0) { return fn.apply(this, args); } else { [].push.apply(args, arguments); // 返回函數本身,這里指向 return 后面的匿名函數! return arguments.callee; } } };

var cost = (function() { // 閉包存儲最后的值 var money = 0;

return function() { for (var i = 0, len = arguments.length; i < len; i++) { money += arguments[i]; }

return money;

} })();

// 轉化成 currying 函數 // 這個時候,閉包內部的 fn 指向真正的求值函數 // 也就是 cost 自運行的時候返回的匿名函數 var cost = currying(cost);

cost(200); cost(300); cost(500);

// 求值輸出 console.log(cost());</code></pre>

2、uncurrying 函數

Function.prototype.uncurrying = function() {
  // 此時 selft 是后面例子中的 Array.prototype.push;
  var self = this;

return function() { // arguments: { '0': { '0': 1, length: 1 }, '1': 2 } var obj = Array.prototype.shift.call(arguments); return self.apply(obj, arguments); } };

// 另外一種實現方式 Function.prototype.uncurrying = function() { var self = this;

return function() { return Function.prototype.call.apply(self, arguments); } };

var push = Array.prototype.push.uncurrying();

var obj = { "length": 1, "0": 1 };

push(obj, 2); console.log(obj);</code></pre>

3、函數節流

JavaScript 中的函數大多數情況下都是由用戶主動調用觸發的,除非是函數本身的實現不合理,否則我們一般不會遇到跟性能相關的問題。但是在一些少數情況下,函數的觸發不是有由用戶直接控制的。在這些場景下,函數有可能被非常頻繁的調用,而造成大的性能問題。

函數被頻繁調用的場景:

  • window.onresize 事件

  • mousemove 事件

  • 上傳進度

函數節流原理

上面三個提到的場景,可以發現它們面臨的共同問題是函數被觸發的頻率太高。

比如我們在 window.onresize 事件中要打印當前瀏覽器窗口大小,在我們拖拽改變窗口大小的時候,控制臺1秒鐘進行了 10 次。而我們實際上只需要 2 次或者 3 次。這就需要我們按時間段來忽略掉一些事件請求,比如確保在 500ms 內打印一次。很顯然,我們可以借助 setTimeout 來完成。

函數節流實現

/**

  • 函數節流實現
  • @param {Function} fn 需要節流執行的函數
  • @param {[type]} interval 事件執行間隔時間,單位 ms
  • @return {[type]} [description] */ var throttle = function(fn, interval) { var _self = fn, timer, firstTime = true;

    console.log(_self);

    return function() { var args = arguments,

     _me = this;  // 這里代表當前的匿名函數
    
    

    console.log(_me);

    if (firstTime) { _self.apply(_me, args); return firstTime = false; }

    if (timer) { return false; }

    timer = setTimeout(function() { clearTimeout(timer); timer = null; _self.apply(_me, args); }, interval || 500); }; };

window.onresize = throttle(function() { console.log('test'); }, 500);</code></pre>

4、分時函數

我們經常會遇到這么一種情況,某些函數確實是用戶主動調用的,但是因為一些客觀原因,這些函數會嚴重地影響頁面性能。

一個例子就是創建 WebQQ 的 QQ 好友列表。列表中通常會有成百上千個好友,如果一個好友用一個節點來表示,當我們在頁面中渲染這個列表的時候,可能要一次性往頁面中創建成百上千個節點。

在短時間內往頁面中大量添加 DOM 節點顯然也會讓瀏覽器吃不消,我們看到的結果往往就是瀏覽器的卡頓甚至假死。所以我們需要一個分時函數來解決這個問題

/**

  • 分時函數例子
  • 以創建 WebQQ 列表為例
  • @param {[type]} data 函數執行需要用到的數據
  • @param {Function} fn 真正需要分時執行的函數
  • @param {[type]} count 每次創建一批節點的數量
  • @param {[type]} interval 函數執行間隔
  • @return {[type]} [description] */ var timeChunk = function(data, fn, count, interval) { var t;

    var len = data.length;

    var start = function() { for (var i = 0; i < Math.min(count || 1, data.length); i++) { var obj = data.shift(); fn(obj); } }

    return function() { t = setInterval(function() { if (data.length === 0) {

     return clearInterval(t);
    

    }

    start(); }, interval); } }</code></pre>

    5、惰性加載函數

    以創建事件綁定函數為例:

    在進入第一個條件分支之后,在函數內部重寫這個函數,重寫之后,就是我們所需要的函數,在下一次進入的時候,就不再需要判斷了。

    /**

  • 事件綁定
  • @param {[type]} el [description]
  • @param {[type]} type [description]
  • @param {[type]} handler [description] */ var addEvent = function(el, type, handler) { if (window.addEventListener) { addEvent = function(el, type, handler) { el.addEventListener(type, handler, false); } } else if (window.attachEvent) { addEvent = function(el, type, handler) { el.attachEvent('on' + type, handler); } }

    addEvent(el, type, handler); }</code></pre>

    Q&A

    暫時這么多,以后會不定期更新一些關于我讀這本書的筆記內容!

     

     

 本文由用戶 RedaVNUM 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!