• js高阶函数


    高阶函数定义(至少满足下面条件之一的函数) - 《javascript 设计模式开发与实践》

    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 - reduce 等等)

    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> 
    
    
  • 相关阅读:
    tmux工具,终端复用
    使用sgdisk进行磁盘分区
    「Spring Boot 2.4 新特性」启动耗时详细监控
    「Spring Boot 2.4 新特性」启动耗时详细监控
    「SpringBoot2.4新特性」jar自动瘦身
    Spring Boot 2.4 新特性,全新的Cron表达式处理机制
    「Spring Boot 2.4 新特性」一键构建Docker镜像
    Spring Boot 接口幂等插件使用
    Druid 监控分布式解决方案
    Ehcache 入门详解 (转)
  • 原文地址:https://www.cnblogs.com/honkerzh/p/10619458.html
Copyright © 2020-2023  润新知