[读书笔记]高阶函数
1. 什么是高階函數(shù)
- 函數(shù)可以作為參數(shù)被傳遞;
- 函數(shù)可以作為返回值輸出。
2. 高階函數(shù)的示例
2.1 函數(shù)作為參數(shù)傳遞
(1) 回調(diào)函數(shù)(callback)
回調(diào)函數(shù)類似于C#中的委托,在異步操作中應(yīng)用較為廣泛。如jQuery中的ajax:
1 var getOrderInfo = function (callback) { 2 $.ajax({ 3 type: 'POST', 4 url: '/URL', 5 data: "name=John&location=Boston", 6 dataType: "json", 7 }).then(function (data) { 8 if (typeof callback === 'function') { 9 // render 10 callback(data); 11 } 12 }, function () { 13 console.error('error'); 14 }); 15 };(2) Array.prototype.sort
將排序規(guī)則作為回調(diào)函數(shù)傳給Array.prototype.sort方法來得到想要的排序結(jié)果:
1 var s1 = [ 2 { name: '李雷', age: 12 }, 3 { name: '陳梅梅', age: 11 }, 4 { name: '露西', age: 11 }, 5 { name: '大衛(wèi)', age: 13 } 6 ], 7 s2 = [].concat(s1), 8 ageAsc = function (a, b) { 9 return a.age - b.age; 10 }, 11 ageDesc = function (a, b) { 12 return b.age - a.age; 13 }; 14 // 年齡從小到大 15 s1.sort(ageAsc); 16 console.dir(s1); 17 // 年齡大到小 18 s2.sort(ageDesc); 19 console.info(s2);2.2 函數(shù)作為返回值輸出
(1) 判斷數(shù)據(jù)類型
1 var isType = function( type ){ 2 return function( obj ){ 3 return Object.prototype.toString.call( obj ) === '[object '+ type +']'; 4 } 5 }, 6 isString = isType( 'String' ), 7 isArray = isType( 'Array' ), 8 isNumber = isType('Number'); 9 console.log(isString); // 輸出isString 10 /* 11 function( obj ){ 12 return Object.prototype.toString.call( obj ) === '[object '+ type +']'; 13 } 14 */(2) 獲取單例
1 var getSingle = function (fn) { 2 var ret; 3 return function () { 4 return ret || (ret = fn.apply(this, arguments)); 5 }; 6 }, 7 getScript = getSingle(function () { 8 return document.createElement('script'); 9 }); 10 11 var script1 = getScript(), // 第一次調(diào)用時將執(zhí)行 (ret = fn.apply(this, arguments) 12 script2 = getScript(); // 第二次調(diào)用時直接返回 ret 13 console.log('script1 === script2 is ', script1 === script2); // 輸出:true3. 高階函數(shù)的應(yīng)用
3.1 高階函數(shù)實現(xiàn)AOP
提起AOP(面向切面編程),可能會想起Spring MVC 中的AOP。實現(xiàn)如下:
1 Function.prototype.before = function (beforefn) { 2 var that = this; // 保存原函數(shù)的引用 3 console.log(that); // that指向print2() 4 // 返回包含了原函數(shù)和新函數(shù)的"代理"函數(shù) 5 // return#1 6 return function () { 7 beforefn.apply(this, arguments); // 執(zhí)行新函數(shù),修正this 8 return that.apply(this, arguments); // 執(zhí)行原函數(shù) 9 }; 10 }; 11 12 Function.prototype.after = function (afterfn) { 13 var that = this; // 保存原函數(shù)的引用 14 console.log(that); // that 指向return#1 15 // return#2 16 return function () { 17 var ret = that.apply(this, arguments); // 執(zhí)行原函數(shù),并保存原函數(shù)的執(zhí)行結(jié)果 18 afterfn.apply(this, arguments); // 執(zhí)行新函數(shù) 19 return ret; // 在新函數(shù)執(zhí)行完成之后返回原函數(shù)的執(zhí)行結(jié)果 20 }; 21 }; 22 23 var print1 = function () { 24 console.log(1); 25 }, 26 print2 = function () { 27 console.log(2); 28 }, 29 print3 = function () { 30 console.log(3); 31 }; 32 33 print2 = print2.before(print1).after(print3); 34 print2();3.2 柯里化(currying)
currying 又稱部分求值。一個currying 的函數(shù)首先會接受一些參數(shù),接受了這些參數(shù)之后,
該函數(shù)并不會立即求值,而是繼續(xù)返回另外一個函數(shù),剛才傳入的參數(shù)在函數(shù)形成的閉包中被保
存起來。待到函數(shù)被真正需要求值的時候,之前傳入的所有參數(shù)都會被一次性用于求值。
3.3 反柯里化(uncurrying)
1 Function.prototype.uncurrying = function () { 2 var self = this; 3 return function () { 4 return Function.prototype.call.apply(self, arguments); 5 } 6 }; 7 8 var push = Array.prototype.push.uncurrying(); 9 10 var obj = { 11 name: 'wills', 12 age: 26 13 }; 14 push(obj, 'JavaScript programer'); 15 16 console.log(obj); // Object {0: "JavaScript programer", name: "wills", age: 27, length: 1}3.4 函數(shù)節(jié)流
函數(shù)節(jié)流目的即降低函數(shù)被頻繁調(diào)用的頻率。代碼實現(xiàn)如下:
1 // 函數(shù)節(jié)流 2 var throttle = function (fn, interval) { 3 var __self = fn, // 保存需要被延遲執(zhí)行的函數(shù)引用 4 timer, // 定時器 5 firstTime = true; // 是否是第一次調(diào)用 6 7 return function () { 8 var args = arguments, 9 that = this; 10 11 // 如果是第一次調(diào)用,不需延遲執(zhí)行 12 if (firstTime) { 13 __self.apply(that, args); 14 return firstTime = false; 15 } 16 17 if (timer) { // 如果定時器還在,說明前一次延遲執(zhí)行還沒有 18 return false; 19 } 20 21 timer = setTimeout(function () { // 延遲一段時間執(zhí)行 22 clearTimeout(timer); 23 timer = null; 24 __self.apply(that, args); 25 }, interval || 500); 26 }; 27 }; 28 29 var resizeThrottle = throttle(function () { 30 console.log(1); 31 }, 500), 32 resize = function () { 33 console.log(2); 34 }; 35 window.onresize = function () { 36 resizeThrottle(); 37 resize(2); 38 };3.5 分時函數(shù)
?分時函數(shù)與函數(shù)節(jié)流相似,使用場景一般為主動調(diào)用。
1 var ary = []; 2 for (var i = 1; i <= 1000; i++) { 3 ary.push(i); // 假設(shè)ary 裝載了1000 個好友的數(shù)據(jù) 4 }; 5 var renderFriendList = function (data) { 6 for (var i = 0, l = data.length; i < l; i++) { 7 var div = document.createElement('div'); 8 div.innerHTML = i; 9 document.body.appendChild(div); 10 } 11 }; 12 renderFriendList(ary); 未使用分時函數(shù)優(yōu)化前使用分時函數(shù)之后:
var timeChunk = function (ary, fn, count) {/// <summary>/// 分時函數(shù)/// </summary>/// <param name="ary" type="Array">數(shù)據(jù)(對象)數(shù)組</param>/// <param name="fn" type="Function">函數(shù)</param>/// <param name="count" type="Number">每次執(zhí)行的數(shù)組長度</param>var obj,t,len = ary.length,start = function () {for (var i = 0; i < Math.min(count || 1, ary.length) ; i++) {var obj = ary.shift();fn(obj);}};return function () {t = setInterval(function () {if (ary.length === 0) { // 如果全部節(jié)點都已經(jīng)被創(chuàng)建好return clearInterval(t);}start();}, 200); // 分批執(zhí)行的時間間隔,也可以用參數(shù)的形式傳入 }; };var ary = []; for (var i = 1; i <= 1000; i++) {ary.push(i); }; var renderFriendList = timeChunk(ary, function (n) {var div = document.createElement('div');div.innerHTML = n;document.body.appendChild(div); }, 8);renderFriendList();3.6 惰性加載函數(shù)
?
1 var addEvent = function (elem, type, handler) { 2 console.log('addEvent'); 3 if (window.addEventListener) { 4 console.log('addEventListener'); 5 addEvent = function (elem, type, handler) { 6 elem.addEventListener(type, handler, false); 7 } 8 } else if (window.attachEvent) { 9 console.log('attachEvent'); 10 addEvent = function (elem, type, handler) { 11 elem.attachEvent('on' + type, handler); 12 } 13 } 14 addEvent(elem, type, handler); 15 }; 16 17 var div = document.getElementById('div1'); 18 addEvent(div, 'click', function () { 19 alert(1); 20 }); 21 addEvent(div, 'click', function () { 22 alert(2); 23 });?
轉(zhuǎn)載于:https://www.cnblogs.com/January/p/5430764.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的[读书笔记]高阶函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: static方法与非static方法是否
- 下一篇: 链剖LCT总结