前言
开发中常见的开发技巧、面试中长谈的设计模式,自然少不了这三个兄弟了~
防抖
应用场景:
- 按钮点击防止多次触发
- 下拉框输入监听延迟搜索功能
window.onresize监听窗口变化
/**
* @desc 函数防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true 表立即执行,false 表非立即执行
*/
function debounce(func,wait,immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
} else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
节流
应用场景:
- 滚动条监听
- 上拉加载获取数据
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
*/
function throttle(func, wait ,type) {
if(type===1){
let previous = 0;
}else if(type===2){
let timeout;
}
return function() {
let context = this;
let args = arguments;
if(type===1){
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
} else if(type===2){
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}
柯里化
柯里化说实话第一次听到的时候,感觉很奇妙,很高级,但实际上理解了含义后,其实也没什么大不了的呀~
官方介绍:
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
这段话还是直接看代码来理解吧~
简单应用
// 函数封装后
function check(reg, txt) {
return reg.test(txt)
}
check(/\d+/g, 'test') //false
check(/[a-z]+/g, 'test') //true
// Currying后
function curryingCheck(reg) {
return function(txt) {
return reg.test(txt)
}
}
var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)
hasNumber('test1') // true
hasNumber('testtest') // false
hasLetter('21212') // false
从这里可以看出来,其本质就是用了闭包,相当于一个工厂模式,对特定规则进行加工,产出对应功能的工具。
最常见的应用就是 Function.prototype.bind 就是典型的柯里化了
那有一个问题,关于官方描述的,可能需要满足于这种需求:
通用封装实现 currying(a)(b)(c) 模式
这里本人按照要求完成了下面一个小栗子:
function createCurrying(fn) {
var _this = this
var len = fn.length;
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var newArgs = args.concat(Array.prototype.slice.call(arguments));
var _args = [];
for (var i = 0; i < newArgs.length; i += 1) {
_args.push('newArgs[' + i + ']');
}
// 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
if (newArgs.length < len) {
return eval('createCurrying.call(_this, fn, ' + _args + ')')
}
// 参数收集完毕,则执行fn
return fn.apply(this, newArgs);
}
}
var currying = createCurrying(
function (a,b,c,d) { console.log(a,b,c,d) }, '1', '2'
);
currying('3')('4'); // 输出: 1, 2, 3, 4