摘要:設計模式與開發實踐讀書筆記最近利用碎片時間在上面閱讀設計模式與開發實踐讀書這本書,剛開始閱讀前兩章內容,和大家分享下我覺得可以在項目中用的上的一些筆記。事件綁定暫時這么多,以后會不定期更新一些關于我讀這本書的筆記內容
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());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);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);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); } }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); }Q&A
暫時這么多,以后會不定期更新一些關于我讀這本書的筆記內容!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86407.html
摘要:獨立出來的函數更加容易被改寫,減少維護成本。例如一個分頁函數,函數接受一個表示挑戰頁碼,在跳轉前需要判斷是否在有效的取值范圍。面向對象設計鼓勵將行為分布在合理數量的更小對象之中。 這是《 javaScript設計模式與開發實踐 》一書的最后一章代碼重構。 以下的一些方法不是必須嚴格遵守的標準,選擇實踐哪些,以及如何實現這都需根據情況而定(是不是有充足時間) 提煉函數 如果在函數中有一...
摘要:訂閱模式的一個典型的應用就是后面會寫一篇相關的讀書筆記。享元模式享元模式的核心思想是對象復用,減少對象數量,減少內存開銷。適配器模式對目標函數進行數據參數轉化,使其符合目標函數所需要的格式。 設計模式 單例模式 JS的單例模式有別于傳統面向對象語言的單例模式,js作為一門無類的語言。使用全局變量的模式來實現單例模式思想。js里面的單例又分為普通單例和惰性單例,惰性單例指的是只有這個實例...
摘要:除此以外,讓元素脫離文檔流也是一個很好的方法。因為元素一旦脫離文檔流,它對其他元素的影響幾乎為零,性能的損耗就能夠有效局限于一個較小的范圍。講完重排與重繪,往元素上綁定事件也是引起性能問題的元兇。高性能這本書非常精致,內容也非常豐富。 showImg(https://segmentfault.com/img/bVJgbt?w=600&h=784); 入手《高性能JavaScript》一...
摘要:最近閱讀了編寫可維護的,在這里記錄一下讀書筆記。禁止使用,,,的字符串形式。避免使用級事件處理函數。讓事件處理程序成為接觸到對象的唯一函數。檢測函數是檢測檢測函數的最佳選擇。為特定瀏覽器的特性進行測試,并僅當特性存在時即可應用特性檢測。 最近閱讀了《編寫可維護的 JavaScript》,在這里記錄一下讀書筆記。書中主要基于三個方向來講解怎么增加代碼的可維護性:編程風格、編程實踐、自動化...
摘要:盡管在類庫中,可能會經常用到通常和操作有關,另外三種用法即使也非常罕見。一個通用的原則是,禁止使用,并且只在別無他法時使用,。和也是可以使用的,但不要用字符串形式而要用函數 再javascript中,eval()的參數是一個字符串,eval()會將傳入的字符串當做代碼來執行,開發者可以通過這個函數來載入外部的javascript代碼,活著隨機生成Javascript代碼并執行它,比如:...
閱讀 2109·2023-04-26 00:50
閱讀 2479·2021-10-13 09:39
閱讀 2201·2021-09-22 15:34
閱讀 1605·2021-09-04 16:41
閱讀 1336·2019-08-30 15:55
閱讀 2433·2019-08-30 15:53
閱讀 1707·2019-08-30 15:52
閱讀 748·2019-08-29 16:19