- 惰性函数
特点:懒、能执行一次的绝对不会执行第二次
<script>
//如此编写,每一次执行方法都需要处理兼容:其实这种操作是没有必要的,第一次执行已经知道兼容情况了,后期在执行方法(浏览器也没有刷新,也没有换浏览器)兼容校验是没必要处理的
function getCss(element,attr){
if(window.getComputedStyle){
return window.getComputedStyle(element)[attr];
}
//IE6~8
return element.currentStyle[attr];
}
//改进:页面一加载就把是否兼容处理了,后期执行方法直接基于变量的值判断使用哪个方法即可
let isCompatible='getComputedStyle' in window;
function getCss(element,attr){
if(isCompatible){
return window.getComputedStyle(element)[attr];
}
//IE6~8
return element.currentStyle[attr];
}
//惰性函数来解决:函数重构
//getCss是全局函数
//第一次执行会产生闭包
function getCss(element,attr){
// EC(1)闭包
// element:body
// attr:width
// 作用域链:<EC(1),EC(G)>
if(window.getComputedStyle){
//把全局的getCss重构成为具体的小函数
getCss=function (element,attr){
return window.getComputedStyle(element)[attr];
};
}else{
getCss=function (element,attr){
return element.currentStyle[attr];
}
}
//重构后首先执行一次,确保第一次调用getCss也可以获取到自己想要的结果
return getCss(element,attr);
}
console.log(getCss(document.body,'width'));
//第二次执行:执行的是重构后的小函数,这样告别了兼容校验的操作
console.log(getCss(document.body,'padding'));
console.log(getCss(document.body,'margin'));
</script>
- 柯里化函数
预处理思想、应用的也是闭包的机制
(1)ES6中的剩余运算符:…args,把传递进来的实参获取到(排除基于其他形参获取的信息)
<script>
function fn(...args){
console.log(args); //数组集合
console.log(arguments); //类数组集合
}
fn(1,2);
</script>
(2)柯里化函数:第一次执行大函数,形成一个闭包(原因:返回一个小函数),把一些信息存储到闭包中(传递的实参信息或当前闭包中声明的一些私有变量等信息);等到后来需要把返回的小函数anonymous执行,遇到一些非自己私有变量,则向其上级上下文中查找(也就是把之前存储在闭包中的信息获取到):如下的代码
<script>
function fn(...outerArgs){
//outerArgs存放第一次执行fn传递的实参信息[1,2]
return function anonymous(...innerArgs){
//innerArgs存放第二次执行匿名函数传递执行实参信息[3]
let arr=outerArgs.concat(innerArgs);
return arr.reduce(function (total,item){
return total+item;
})
}
}
let res=fn(1,2)(3);
console.log(res); //返回结果是1+2+3=6
</script>
- reduce:数组中用来迭代遍历每一项的
(1)
<script>
// arr.reduce(function([result],[item]){
// [result]
// 和callback的同级级别中
//如果传递了[value]值,则第一次执行callback,里面的[result]存储的是参数信息;
//同时item迭代的是数组中的第一项
// }[,value])
let arr=[10,20,30,40];
arr.reduce(function(result,item){
console.log(result,item); //result=0 item=10(数组中的第一项)
},0);
arr.reduce(function(result,item){
console.log(result,item); //result=10 item=20 分别是数组中的第一项和第二项
})
</script>
(2)
<script>
let arr=[10,20,30,40];
let n=arr.reduce(function(total,item){
//把当前callback执行返回的结果,做为下一次迭代中的[result]处理
return total+item;
},0);
console.log(n);
</script>
- 自己实现reduce
<script>
function reduce(arr,callback,init){
arr=arr.slice(0);
if(init===undefined){
init=arr[0];
arr=arr.slice(1);
}
for(let i=0;i<arr.length;i++){
let item=arr[i];
index=i;
init=callback(init,item,index);
}
return init;
}
let arr=[10,20,30,40];
let result=reduce(arr,function (result,item,index){
return result+item;
});
console.log(result);
result=reduce(arr,function (result,item,index){
return result+item;
},100);
console.log(result);
</script>
在传值的时候index是从0开始的,在没有传值的时候index是从1开始的,reduce函数的改进(最全的情况),如下所示:
function reduce(arr,callback,init){
arr=arr.slice(0);
let result=init;
for(let i=0;i<arr.length;i++){
if(init===undefined && i===0){
// init没有传递值(只有第一轮特殊)
result=arr[0];
let item=arr[1],
index=1;
//只有一项的时候,index没有值,所以直接返回结果
if(!item) return result;
result=callback(result,item,index);
i++;
// break;
continue;
}
//init传递值了
let item=arr[i],
index=i;
result=callback(result,item,index);
}
return result;
}