基于闭包的高阶单例模式
let module1 = (function () {
function query() {}
function tools() {}
return {
name: 'AREA',
tools
};
})();
module1.tools();
惰性思想:懒,执行过一遍的东西,如果第二遍执行还是一样的效果,则我们就不想让其重复执行第二遍了
function getCss(element, attr) {
if ('getComputedStyle' in window) {
return window.getComputedStyle(element)[attr];
}
return element.currentStyle[attr];
}
function getCss(element, attr) {
if ('getComputedStyle' in window) {
getCss = function (element, attr) {
return window.getComputedStyle(element)[attr];
};
} else {
getCss = function (element, attr) {
return element.currentStyle[attr];
};
}
// 为了第一次也能拿到值
return getCss(element, attr);
}
getCss(document.body, 'margin');
getCss(document.body, 'padding');
getCss(document.body, 'width');
柯理化函数思想:利用闭包保存机制,把一些信息预先存储下来(预处理的思想)
题目
let res = fn(1, 2)(3);
console.log(res); //=>6 1+2+3
function fn(...outerArgs) {
return function anonymous(...innerArgs) {
// ARGS:外层和里层函数传递的所有值都合并在一起
let args = outerArgs.concat(innerArgs);
return args.reduce((n, item) => n + item);
};
}
let f = fn(10, 20, 30);
console.log(f(40)) // 100
console.log(f(100)) // 160
let res = fn(1, 2)(3);
console.log(res); //=>6 1+2+3
把多层函数嵌套调用扁平化展开
const fn1 = (x, y) => x + y + 10;
const fn2 = x => x - 10;
const fn3 = x => x * 10;
const fn4 = x => x / 10;
function compose(...funcs) {
// FUNCS:存储按照顺序执行的函数(数组) =>[fn1, fn3, fn2, fn4]
return function anonymous(...args) {
// ARGS:存储第一个函数执行需要传递的实参信息(数组) =>[20]
if (funcs.length === 0) return args;
if (funcs.length === 1) return funcs[0](...args);
return funcs.reduce((N, func) => {
// 第一次N的值:第一个函数执行的实参 func是第一个函数
// 第二次N的值:上一次func执行的返回值,作为实参传递给下一个函数执行
return Array.isArray(N) ? func(...N) : func(N);
}, args);
};
}
let res = compose(fn1, fn3, fn2, fn4)(20, 30);
console.log(res);
react中的redux源码中的compose函数用的是另外思想实现的
防抖:在用户频繁触发的时候,我们只识别一次(识别第一次/识别最后一次)
function func() {
console.log('OK');
}
// 防止频繁点击触发:设置标识进行判断
let isClick = false;
document.body.onclick = function () {
if (isClick) return;
isClick = true;
setTimeout(() => {
console.log('OK');
isClick = false;
}, 1000);
};
存在问题:只能控制执行间隔
function debounce(func, wait = 500, immediate = false) {
let timer = null;
return function anonymous(...params) {
let now = immediate && !timer; // timer设置了定时器,说明就不是第一次执行了
clearTimeout(timer); // wait 时间内,如果再次触发就清除上一次的定时器
timer = setTimeout(() => {
timer = null;
// 执行函数:注意保持THIS和参数的完整度
!immediate ? func.call(this, ...params) : null;
}, wait);
// 只执行第一次
now ? func.call(this, ...params) : null;
};
}
function func() {
console.log("点击了");
}
document.body.onclick = debounce(func, 1000, true);
比如浏览器滚动事件,浏览器检测到滚动就会触发很多次绑定的事件,也就是说函数的执行频率很高
而节流就是为了缩减这个频率而诞生的
和防抖的区别就在于节流是缩减频率而不是限定为只执行一次
实现
function throttle(func, wait = 500) {
let timer = null,
previous = 0; //记录上一次操作时间
return function anonymous(...params) {
let now = new Date(), //当前操作的时间
remaining = wait - (now - previous);
if (remaining <= 0) {
// 两次间隔时间超过频率:把方法执行即可
clearTimeout(timer);
timer = null;
previous = now;
func.call(this, ...params);
}
if (remaining > 0 && !timer) { // 如果有定时器就不需要再定时,先把上一次的执行完成再说
// 两次间隔时间没有超过频率,说明还没有达到触发标准,设置定时器等待即可(还差多久等多久)
timer = setTimeout(() => {
clearTimeout(timer);
timer = null;
previous = new Date();
func.call(this, ...params);
}, remaining);
}
};
}
function func() {
console.log("滚动了");
}
document.body.onscroll = throttle(func, 500);