js高阶函数

更新日期: 2019-03-31 阅读: 2.8k 标签: 函数

高阶函数定义(至少满足下面条件之一的函数) 

1.函数作为形参传递
2.函数作为返回值输出


1.函数作为形式参数传递

a.回调函数(异步回调,达到异步执行条件将回调函数放入执行队列中执行)
var appendDiv = function( callback ){ 
     for ( var i = 0; i < 100; i++ ){ 
         var div = document.createElement( 'div' ); 
         div.innerhtml = i; 
         document.body.appendChild( div ); 
         if ( typeof callback === 'function' ){ 
             callback( div ); 
         } 
     } 
}; 
appendDiv(function( node ){ 
 node.style.display = 'none'; 
}); 

b.Array.prototype.sort 类型函数 (Array.prototype.every - some -forEach-map 等等)

Array.prototype.sort 接受一个函数当作参数,这个函数里面封装了数组元素的排序规则。从Array.prototype.sort 的使用可以看到,我们的目的是对数组进行排序,这是不变的部分;而使用什么规则去排序,则是可变的部分。把可变的部分封装在函数参数里,动态传入
Array.prototype.sort,使 Array.prototype.sort 方法成为了一个非常灵活的方法。

let arr = [2,1,3];
arr.sort((a,b)=>{
    return a - b;        //a-b 从小到大,b-a 从大到小
})
console.log(arr);             //[1,2,3]


2.函数作为返回值输出(比如我们最常见的闭包)

var getSingle = function ( fn ) { 
     var ret; 
     return function () { 
         return ret || ( ret = fn.apply( this, arguments ) ); 
 }; 
}; 
//这个高阶函数的例子,既把函数当作参数传递,又让函数执行后返回了另外一个函数。我们
//可以看看 getSingle 函数的效果:
var getScript = getSingle(function(){ 
     return document.createElement( 'script' ); 
}); 
var script1 = getScript(); 
var script2 = getScript(); 
alert ( script1 === script2 ); // 输出:true 


3.高阶函数实现AOP

AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等。把这些功能抽离出来之后,再通过“动态织入”的方式掺入业务逻辑模块中。这样做的好处首先是可以保持业务逻辑模块的纯净和高内聚性,其次是可以很方便地复用日志统计等功能模块通常,在 JavaScript 中实现 AOP,都是指把一个函数“动态织入”到另外一个函数之中,具体的实现技术有很多,本节我们通过扩展 Function.prototype 来做到这一点。代码如下:

Function.prototype.before = function( beforefn ){ 
     var __self = this; // 保存原函数的引用
     return function(){ // 返回包含了原函数和新函数的"代理"函数
         beforefn.apply( this, arguments ); // 执行新函数,修正 this 
         return __self.apply( this, arguments ); // 执行原函数
     } 
}; 
Function.prototype.after = function( afterfn ){ 
     var __self = this; 
     return function(){ 
         var ret = __self.apply( this, arguments ); 
         afterfn.apply( this, arguments ); 
         return ret; 
     } 
}; 
var func = function(){ 
     console.log( 2 ); 
}; 
func = func.before(function(){ 
     console.log( 1 ); 
}).after(function(){ 
     console.log( 3 ); 
}); 
func();//1 2 3


4.柯里化(currying)

currying 又称部分求值。一个 currying 的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。

var cost = (function(){ 
     var args = []; 
     return function(){ 
         if ( arguments.length === 0 ){ 
             var money = 0; 
             for ( var i = 0, l = args.length; i < l; i++ ){ 
                 money += args[ i ]; 
            } 
             return money; 
         }else{ 
             [].push.apply( args, arguments ); 
         } 
     } 
})(); 
cost( 100 ); // 未真正求值
cost( 200 ); // 未真正求值
cost( 300 ); // 未真正求值
console.log( cost() ); // 求值并输出:600 


5.节流 - 函数被触发的频率太高。

实现:通过闭包来实现
一个简单的例子:

//节流
let jieliu = (function (){
    let ajax = true;
    return function(){
        console.log(ajax);
        if(ajax){
            ajax = false;
            let time = setTimeout(function(){
            ajax = true;
            console.log('ajaxing');
        },5000);
        }
    }
})();
document.getElementById('test').onclick = jieliu;


6.分时函数

某些函数确实是用户主动调用的,但因为一些客观的原因,这些函数会严重地影响页面性能在短时间内往页面中大量添加 dom 节点显然也会让浏览器吃不消,我们看到的结果往往就是浏览器的卡顿甚至假死。代码如下:

var ary = []; 
for ( var i = 1; i <= 10000000; i++ ){ 
     ary.push( i ); // 假设 ary 装载了 10000000 个好友的数据
}; 
var renderFriendList = function( data ){ 
     for ( var i = 0, l = data.length; i < l; i++ ){ 
         var div = document.createElement( 'div' ); 
         div.innerHTML = i; 
         document.body.appendChild( div ); 
     } 
}; 
renderFriendList( ary );   //哈哈,界面直接提示崩溃啦

解决方案:分时函数 - 利用setTimeout 每隔一段时间创建dom节点加入界面中,缓解一次性添加过多dom结点造成的低性能问题

var timeChunk = function( ary, fn, count ){ 
    var obj, 
        t; 
    var len = ary.length; 
    var 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 <= 10000000; i++ ){ 
    ary.push( i ); 
 }; 
 var renderFriendList = timeChunk( ary, function( n ){ 
    var div = document.createElement( 'div' ); 
    div.innerHTML = n; 
    document.body.appendChild( div ); 
 }, 12 ); 
 renderFriendList(); 


7.惰性加载函数

在 Web 开发中,因为浏览器之间的实现差异,一些嗅探工作总是不可避免。比如我们需要一个在各个浏览器中能够通用的事件绑定函数 addEvent
新手写法:

var addEvent = function( elem, type, handler ){ 
     if ( window.addEventListener ){ 
         return elem.addEventListener( type, handler, false ); 
    } 
     if ( window.attachEvent ){ 
         return elem.attachEvent( 'on' + type, handler ); 
     } 
}; //缺点是当它每次被调用的时候都会执行里面的 if 条件分支,虽然执行这些 if分支的开销不算大,但也许有一些方法可以让程序避免这些重复的执行过程。 

进阶写法:

var addEvent = (function(){ 
     if ( window.addEventListener ){ 
         return function( elem, type, handler ){ 
             elem.addEventListener( type, handler, false ); 
         } 
     } 
     if ( window.attachEvent ){ 
         return function( elem, type, handler ){ 
            elem.attachEvent( 'on' + type, handler ); 
         } 
     } 
})();  //我们把嗅探浏览器的操作提前到代码加载的时候,在代码加载的时候就立刻进行一次判断,以便让 addEvent 返回一个包裹了正确逻辑的函数。

缺点:也许我们从头到尾都没有使用过 addEvent 函数,这样看来,前一次的浏览器嗅探就是完全多余的操作,而且这也会稍稍延长页面 ready 的时间。

老司机写法: - 惰性载入函数方案

<html> 
  <body> 
   <div id="div1">点我绑定事件</div> 
   <script> 
         var addEvent = function( elem, type, handler ){ 
                 if ( window.addEventListener ){ 
                     addEvent = function( elem, type, handler ){ 
                         elem.addEventListener( type, handler, false ); 
                     } 
                 }else if ( window.attachEvent ){ 
                     addEvent = function( elem, type, handler ){ 
                         elem.attachEvent( 'on' + type, handler ); 
                     } 
                 } 
                 addEvent( elem, type, handler ); 
         }; 
        var div = document.getElementById( 'div1' ); 
             addEvent( div, 'click', function(){ 
             alert (1); 
         }); 
        addEvent( div, 'click', function(){ 
            alert (2); 
        }); 
 </script> 
 </body> 
</html> 

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/2652

相关推荐

JavaScript push() 方法详解

push() 方法主要用于向数组的末尾添加一个或多个元素,其返回值为添加后新的长度,即push后的数组长度,该值为number类型。介绍:一个数组中添加新元素、把一个数组的值赋值到另一个数组上、在对象使用push

什么是纯函数_以及为什么要用纯函数?

当我第一次听到 “纯函数 (Pure Function)” 这个术语的时候我很疑惑。常规的函数做错了什么?为什么要变纯? 为什么我需要纯的函数?除非你已经知道什么是纯函数,否则你可能会问同样的疑惑

让我们来创建一个JavaScript Wait函数

Async/await以及它底层promises的应用正在猛烈地冲击着JS的世界。在大多数客户端和JS服务端平台的支持下,回调编程已经成为过去的事情。当然,基于回调的编程很丑陋的。

什么是函数的副作用——理解js编程中函数的副作用

函数副作用是指当调用函数时,除了返回函数值之外,还对主调用函数产生附加的影响。副作用的函数不仅仅只是返回了一个值,而且还做了其他的事情

js中sort函数用法总结_sort排序算法原理

js中sort方法用于对数组的元素进行排序,并返回数组。默认排序顺序是根据字符串Unicode码点。如果要得到自己想要的结果,不管是升序还是降序,就需要提供比较函数了。该函数比较两个值的大小,然后返回一个用于说明这两个值的相对顺序的数字

javascript封装函数

使用函数有两步:1、定义函数,又叫声明函数, 封装函数。2、调用函数var 变量 = 函数名(实参);对函数的参数和返回值的理解

js中reduce()方法

reduce() 方法接收一个函数作为累加器,reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(上一次回调的返回值),当前元素值,当前索引,原数组。

javascript回调函数的理解和使用方法(callback)

在js开发中,程序代码是从上而下一条线执行的,但有时候我们需要等待一个操作结束后,再进行下一步操作,这个时候就需要用到回调函数。 在js中,函数也是对象,确切地说:函数是用Function()构造函数创建的Function对象。

js调用函数的几种方法_ES5/ES6的函数调用方式

这篇文章主要介绍ES5中函数的4种调用,在ES5中函数内容的this指向和调用方法有关。以及ES6中函数的调用,使用箭头函数,其中箭头函数的this是和定义时有关和调用无关。

js构造函数

JS中的函数即可以是构造函数又可以当作普通函数来调用,当使用new来创建对象时,对应的函数就是构造函数,通过对象来调用时就是普通函数。在我们平时工作中,经常会需要我们创建一个对象,而我们更多的是使用对像直接量,直接创建

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!