概述
不能不写总结
惰性函数
- 概念理解:最理想的状态下执行一次,后续直接使用第一次执行返回的结果即可。
- 情景展现:程序初始访问时不确定客户端支持哪种对象,则需要
if..else
判断,以获取支持的实例化对象。
最典型的的就是浏览器对XHR
的实现。
function createXHR(){
if(typeof XMLHttpRequest!="undefined"){
return new XMLHttpRequest();
}else if(typeof ActiveXObject!="undefined"){
if(typeof arguments.callee.activeXString!="string"){
var version=["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"];
for(var i=0;i<version.length;i++){
try{
new ActiveXObject(version[i]);
arguments.callee.activeXString =version[i];
break;
}catch(ex){
console.log(ex);
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}else{
throw new Error("No XHR valid");
}
}
两种方式实现惰性加载:
-
函数初始化时,该函数会被内部分支中适配的函数覆盖,下次任何对该函数的调用都是适配好的函数。
// 一个日志记录的模块 function log(){ if(user.type==1){ log= function(){ // 可能是一个对象,好多方法 return { print(){ console.log("大佬来了!"); } } } }else if(user.type==2){ log =function() { // 可能是一个对象,好多方法 return { print(){ console.log("一个小菜鸟进来了!"); } } } }else{ log =function() { throw new Error("未知火星人入侵!"); } } return log(); } let user = { // 其他属性 type:1, }; console.log(log().print()); // "大佬来了"
-
声明式,由匿名函数返回适配的函数。
var log = (function(){ if(user.type==1){ return function(){ // 可能是一个对象,好多方法 return { print(){ console.log("大佬来了!"); } } } }else if(user.type==2){ return function() { // 可能是一个对象,好多方法 return { print(){ console.log("一个小菜鸟进来了!"); } } } }else{ return function() { throw new Error("未知火星人入侵!"); } } })();
匿名函数、自执行的函数注意变量的作用范围,
user
对象需在之前声明。
函数柯里化
概念:是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术——来自百度百科
- 把接收多个参数的函数分成两步
- 先传入部分参数由外部函数处理,并返回一个新的函数
- 再在调用这个新函数传入剩余的参数,进行处理。
先感受一下:
function total(fn){
// 调用total时传入了目标处理函数fn,最终是要获取到这个函数处理的结果
// 传入了需要处理的第一个参数 100
let args = Array.prototype.slice.call(arguments,1);
// 返回了一个新的函数,并等待调用
return function(){
// 获取到了剩余的参数
let nextArgs = Array.prototype.slice.call(arguments);
let allArgs = args.concat(nextArgs);
// 调用目标函数 fn ,并返回结果
return fn.apply(null,allArgs);
}
}
let first =total(function(){
console.log(...arguments);
}),100);
first(90); // 100 90
使用柯里化的特点:
- 参数复用, 第一次调用
total
时传入的参数,后续调用新函数一直有效。 提前返回,不是很认同,提前返回是惰性函数载入的特点,是为了减少重复代码的执行。- 延迟计算,第一次调用后不进行第二次调用不会获得结果。
必须写一下bind()
方法的实现:
function bind(fn,context){
let args = Array.prototype.slice.call(arguments,1);
return function(){
let nextArgs = Array.prototype.slice.call(arguments);
let allArgs = args.concat(nextArgs);
return fn.apply(context,allArgs);
}
}
多了一个
context
,执行函数fn
指定其上下文环境。
参考:
张鑫旭大佬的文章,感谢大佬
函数节流、函数防抖
真的是头大,看的红皮书,里面讲的函数节流
实现代码,通过查阅网上资源是函数防抖
实现方式
概念理解:
- 函数节流 ,连续多次调用时,则按照固定频率执行,在固定周期内执行一次
- 函数防抖,在指定周期内,调用
n
次执行1
次(每次调用会刷新初始执行周期,从头计时)
如果有误,还请指正,谢谢!
-
函数防抖
概念:使一个连续重复执行执行的函数间断
执行,使用定时器setTimeout
达到目的初步感受:
function print(){ console.log("doing..."); } for(let i=0;i<30;i++){ print(); // 当然会打印30次 “ding...” }
对这个必须说 No,一样的东西为什么我要执行这么多次,我来一个延时^ _^,看你还怎么执行
let timeId = null; function print(){ clearTimeout(timeId); timeId = setTimeout(function(){ console.log("doing..."); },2000); } // for循环模拟调用 // for(let i=0;i<30;i++){ // print(); // hahahaha 执行一次 “dong...” //} // 定时器模拟 let j=0; let intervalId = setInterval(function(){ if(j>30){ clearInterval(intervalId); } j++; print(); // 打印一次 "doing..." },100);
-
函数节流
概念:连续多次调用时,则按照固定频率执行,在固定周期内执行一次。function print(fn){ let timeId = null; return function(){ if(!timeId){ timeId = setTimeout(function(){ timeId = null; console.log("但是我固定频率执行..."); fn.apply(null,arguments); console.log("-----------分割线-------------"); },2000); } }; } // 注意这里使用了函数柯里化, let obj= print(function(){ console.log("haha"); }); setInterval(function(){ console.log("我在执行..."); obj(); },100);
应用场景:对于较大开销、连续重复执行的事件,比如:
onresize
、onmousemove
等。
纠结了一晚上,也不知道理解的对不对,感觉自己是清楚了。-_-
代码可直接测试执行,查看执行效果
最后
以上就是有魅力香烟为你收集整理的惰性载入函数、函数柯里化、函数节流、函数防抖的全部内容,希望文章能够帮你解决惰性载入函数、函数柯里化、函数节流、函数防抖所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复