JavaScript高级手记(闭包高级应用)
1、闭包应用值惰性函数和柯理化函数
JS高阶编程函数:惰性函数
+ 懒
+ 能只执行一次的绝不会执第二次
function getCss(ele, attr){
if(window.getComputedStyle) {
return window.getComputedStyle(ele)[attr];
} else {
return ele.currentStyle[attr];
}
}
let isComputed = 'getComputedStyle' in window;
function getCss(ele, attr){
if(isComputed) {
return window.getComputedStyle(ele)[attr];
} else {
return ele.currentStyle[attr];
}
}
function getCss(ele, attr){
if(window.getComputedStyle) {
getCss = function(ele, attr) {
return window.getComputedStyle(ele)[attr];
}
} else {
getCss = function(ele, attr) {
return ele.currentStyle[attr];
}
}
return getCss(ele, attr);
}
console.log(getCss(document.body, 'width'));
console.log(getCss(document.body, 'height'));
console.log(getCss(document.body, 'padding'));
* JS高阶函数:柯理化函数
+ 预处理思想:
第一次执行大函数,形成一个闭包(原因:返回了一个小函数),把一些信息存储到闭包中(传递的实参或者当前闭包中声明的以下私有变量等信息);等到后面把返回的小函数(匿名函数)执行的时候,需要用到一些非自己私有的变量,则向上级上下文中查找(也就是把之前存储在闭包中的信息获取到)
+ 应用的也是闭包的机制
function fn(...arg1){
return function(...arg2) {
let arr = arg1.concat(arg2);
return arr.reduce((total, item) => {
return total+ item;
});
};
}
let res = fn(1,2)(3);
console.log(res);
* reduce:数组中用来迭代遍历每一项的
arr.reduce(function([res], [item]) {
})
let arr = [10,20,30,40];
var a = arr.reduce((res, item) =>{
console.log(res, item);
return res + item;
})
console.log(a);
function reduce(arr, callback, init) {
arr = arr.slice(0);
let index = 0;
if(typeof init === 'undefined') {
init = arr[0];
index =1;
}
for(let i=index; i<arr.length; i++) {
init = callback(init, arr[i], i);
}
return init;
}
let arr = [10,20,30,40];
let result = reduce(arr, function(res, item, index){
console.log(index, item);
return res + item;
});
let result1 = reduce(arr, function(res, item, index){
console.log(index, item)
return res + item;
}, 100);
let result2 = reduce([90], function(res, item, index){
console.log(index, item)
return res + item;
});
console.log(result, result1, result2)
2、闭包应用之compose组合函数
在函数式编程当中又以个很重要的概念就是函数组合,实际上就是把处理数据的函数像管道一样连接起来,然后让数据穿过管道得到最终的结果。(有点像高中数学中的复合函数)例如:
const add1 = (x) => x+1;
const mul3 = (x) => x*3;
const div2 = (x) => x/2;
div2(mul3(add1(add1(0))));
而这样的写法可读性太差了,可以构建一个compose函数,它接收多个函数作为参数(这些函数都只接收一个参数),然后compose返回的也是一个函数,从而达到解析复合函数的效果
简而言之:compose函数可以把类似于 f(g(h(x))) 这种写法简化成 compose(f,g,h)(x) 请完成 compose 函数的编写
function compose(...funcs){
return function(x){
if(funcs.length < 1) return x;
let length = funcs.length - 1,
fun = funcs[length];
console.log(fun);
let res = fun(0);
for(let i=length-1; i>=0;i--) {
console.log(funcs[i]);
res = funcs[i](res);
}
console.log(res);
return res;
funcs = funcs.reverse();
console.log(funcs);
return funcs.reduce((res, item) => {
console.log(res, item)
return item(res);
}, x)
}
}
const add1 = (x) => x+1;
const mul3 = (x) => x*3;
const div2 = (x) => x/2;
let re = compose(div2,mul3,add1,add1)(0);
console.log(re);
3、闭包应用之函数的防抖和节流
* 函数的防抖(防止老年帕金森):
对于频繁触发某个操作,只识别一次(执行一次)
@params:
fn [function]:最后要触发执行的函数
wait [number]:“频繁”设定的界限(时间间隔)
immediate [boolean]:触发多次函数时,识别第一次还是最后一次
@return
可以被调用执行的函数
function debounce(fn, wait, immediate=false){
wait = wait || 300;
let timer = null;
return function(ev){
clearTimeout(timer);
console.log(timer);
if(immediate && (timer === null)) {
fn.call(this, ev);
}
timer = setTimeout(()=>{
timer = null;
if(!immediate) {
fn.call(this, ev)
}
}, wait);
}
}
function handle(ev) {
console.log(this, ev);
console.log('防抖');
}
app.onclick = debounce(handle, 500, false);
function throttle(fn, wait=300){
let timer = null,
previous = 0;
return function(ev){
let now = new Date(),
cha = wait - (now - previous);
if(cha <= 0 ){
clearTimeout(timer);
previous = now;
fn.call(this, ev);
} else if(!timer){
timer = setTimeout(() =>{
timer = null;
previous = new Date();
fn.call(this, ev)
},cha)
}
}
}
function handle() {
console.log('节流');
}
window.onscroll = throttle(handle, 500);