1. 什麼是高階函數ajax
2. 高階函數的示例編程
2.1 函數做爲參數傳遞json
(1) 回調函數(callback)數組
回調函數相似於C#中的委託,在異步操做中應用較爲普遍。如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.sortapp
將排序規則做爲回調函數傳給Array.prototype.sort方法來獲得想要的排序結果:異步
1 var s1 = [ 2 { name: '李雷', age: 12 }, 3 { name: '陳梅梅', age: 11 }, 4 { name: '露西', age: 11 }, 5 { name: '大衛', 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 函數做爲返回值輸出ide
(1) 判斷數據類型函數
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(), // 第一次調用時將執行 (ret = fn.apply(this, arguments) 12 script2 = getScript(); // 第二次調用時直接返回 ret 13 console.log('script1 === script2 is ', script1 === script2); // 輸出:true
3. 高階函數的應用
3.1 高階函數實現AOP
提起AOP(面向切面編程),可能會想起Spring MVC 中的AOP。實現以下:
1 Function.prototype.before = function (beforefn) { 2 var that = this; // 保存原函數的引用 3 console.log(that); // that指向print2() 4 // 返回包含了原函數和新函數的"代理"函數 5 // return#1 6 return function () { 7 beforefn.apply(this, arguments); // 執行新函數,修正this 8 return that.apply(this, arguments); // 執行原函數 9 }; 10 }; 11 12 Function.prototype.after = function (afterfn) { 13 var that = this; // 保存原函數的引用 14 console.log(that); // that 指向return#1 15 // return#2 16 return function () { 17 var ret = that.apply(this, arguments); // 執行原函數,並保存原函數的執行結果 18 afterfn.apply(this, arguments); // 執行新函數 19 return ret; // 在新函數執行完成以後返回原函數的執行結果 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 的函數首先會接受一些參數,接受了這些參數以後,
該函數並不會當即求值,而是繼續返回另一個函數,剛纔傳入的參數在函數造成的閉包中被保
存起來。待到函數被真正須要求值的時候,以前傳入的全部參數都會被一次性用於求值。
1 var currying = function (fn) { 2 var args = []; 3 return function () { 4 if (arguments.length === 0) { 5 console.log(this); 6 return fn.apply(this, args); 7 } else { 8 console.log(arguments,args); 9 [].push.apply(args, arguments); 10 // arguments.callee, Returns the Function object being executed 11 return arguments.callee; 12 } 13 } 14 }, 15 cost = (function () { 16 var money = 0; 17 return function () { 18 for (var i = 0, l = arguments.length; i < l; i++) { 19 money += arguments[i]; 20 } 21 return money; 22 } 23 })(); 24 25 var cost = currying(cost); // 轉化成currying 函數 26 cost(100); // 未真正求值 27 cost(200); // 未真正求值 28 cost(300); // 未真正求值 29 console.log(cost()); // 求值並輸出:600
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 函數節流
函數節流目的即下降函數被頻繁調用的頻率。代碼實現以下:
1 // 函數節流 2 var throttle = function (fn, interval) { 3 var __self = fn, // 保存須要被延遲執行的函數引用 4 timer, // 定時器 5 firstTime = true; // 是不是第一次調用 6 7 return function () { 8 var args = arguments, 9 that = this; 10 11 // 若是是第一次調用,不需延遲執行 12 if (firstTime) { 13 __self.apply(that, args); 14 return firstTime = false; 15 } 16 17 if (timer) { // 若是定時器還在,說明前一次延遲執行尚未 18 return false; 19 } 20 21 timer = setTimeout(function () { // 延遲一段時間執行 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 分時函數
分時函數與函數節流類似,使用場景通常爲主動調用。
1 var ary = []; 2 for (var i = 1; i <= 1000; i++) { 3 ary.push(i); // 假設ary 裝載了1000 個好友的數據 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);
使用分時函數以後:
var timeChunk = function (ary, fn, count) { /// <summary> /// 分時函數 /// </summary> /// <param name="ary" type="Array">數據(對象)數組</param> /// <param name="fn" type="Function">函數</param> /// <param name="count" type="Number">每次執行的數組長度</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) { // 若是所有節點都已經被建立好 return clearInterval(t); } start(); }, 200); // 分批執行的時間間隔,也能夠用參數的形式傳入 }; }; 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 惰性加載函數
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 });