函数的柯里化
在我们之前书写函数时,通常函数都是同时接收多个参数来实现功能,
但是在柯里化函数中,就是把这个函数拆分成多个函数,每个被拆分出来的函数接收一个或多个参数来实现功能,通常情况下,外层函数负责接收功能,内层函数负责接收剩余参数或者处理功能并返回结果
简单来说 : 函数柯里化就是我们给一个函数传入一部分参数,此时就会返回一个函数来接收剩余的参数。
1. 简单的柯里化实现
- 普通函数
function sum(a, b, c){
return a + b + c
}
console.log(sum(1, 2, 3)) //6
- 柯里化函数
function sum(a){
return function(b){
return function(c){
return a + b + c
}
}
}
console.log(sum(1)(2)(3)) //6
柯里化函数的封装
1.普通函数
function fn(a, b, c, d) {
return a + b + c + d
}
fn('我', '喜', '欢', 'js')
fn('你', '不', '喜欢', 'js')
上述的代码中只有一个函数,我们可以通过多次传参调用这个函数来实现功能
但是在函数式编程中,我们往往希望一个函数处理的问题尽可能的单一,而不是将一大堆的过程交给一个函数来处理。要符合设计模式中的单一职责原则。
因此我们可以将每次传入的参数在单一的函数中进行处理,处理完后在下一个函数中再使用处理后的结果。
所以在这个时候封装后的柯里化函数就比较符合我们的要求了
2.柯里化函数封装版
function fn(a, b, c, d) {
// console.log(fn.length)//4
return a + b + c + d
}
function curry(callback, ...arg) { // 外层函数: 负责接收参数
/**
* curry 函数需要接受两个参数
* callback: 当参数传递足够时需要执行的函数 => 指向fn
* ...arg: 接收后续这个参数传递所有实参 (以数组的形式存储),加三个点视为了接受后续所有参数
*/
return function (..._arg) { // 内层函数: 负责处理功能
// _arg = [arg, _arg]//两个都是数组,为了方便维护,用es6的展开运算符
_arg = [...arg, ..._arg]
// if ('当前接收参数的数量' === 'fn函数需要的参数数量') {
// '执行 fn 函数'
// } else {
// '此时参数数量不满足函数要求, 需要继续收集参数'
// }
// _arg.length === fn //不能直接写fn,这样就写死了,看看fn给了哪个形参,使用形参来代替fn
//新知识点: 函数.length 可以拿到函数参数的数量
if (_arg.length === callback.length) {
//不能写fn(),这样就写死了,而且参数必须写,不然输出就是undefined
return callback(..._arg)//参数以数组的形式存在,用展开符展开
} else {
// return curry()
//不能直接仅仅调用curry,这样的话之前已经传进来的参数就白传了
return curry(callback, ..._arg)
}
}
}
//直接传递全部参数
let newFn = curry( fn, '我', '喜', '欢', 'js')
console.log(newFn()) //我喜欢js
//分批传递参数
let newFn = curry(fn, '你')
const newFn2 = newFn('不', '喜欢')
const newFn3 = newFn2('js')
console.log(newFn3) //你不喜欢js
自执行函数
实际上不同的人对自执行函数的理解不太一样,第一种理解是,自执行即自动执行,也就是大家平时所谓的立即执行函数。
还有一种理解,即自执行函数是在函数内部执行函数本身,即我们平时常说的递归函数。
但是不管是哪种理解,我们都没必要去纠结叫法上的准确与否,我们更重要的是要明白自执行函数怎么使用, 下面我们结合代码来讲解一下
首先,我们来书写一个普通的函数
function fn(){
console.log('我是普通的函数fn')
}
fn() //我是普通的函数fn
通过代码我们可以以看出,想要执行fn函数,我们需要手动的去调用,
下面我们来感受一下自执行函数
/**
* 加小扩号把上面代码包起来,并且在最后面再加一个小扩号,最前面加一个分号
*
* 自执行函数需要在代码最前边添加一个 分号 ,用于和上一行代码起到一个分割作用
* 如果前面没有需要区分的代码,也可以不加分号
*
* 自执行函数如果需要传参,将实参书写在第二个小括号内即可
*/
;(function fn(num){
console.log('我是自执行的函数fn',num)
})(99)
//输出结果为 : 我是自执行的函数fn, 99
在自执行函数中,我们无需手动去执行函数,函数会自动执行并打印
函数的防抖
防抖
就是指事件在执行时,第一次开始执行时,在结束之前或者指定时间之前,无法触发下一次
除非等到第一次执行结束或者在指定时间到达后,才进行下一次
1.我们以输入框为例讲解防抖
<input type="text" class="inp">
const inp = document.querySelector('.inp')
inp.oninput = (function (flag) {
//当前这个函数会立即执行然后返回f一个函数给到inp.oninput
return function () {
//使用 flag 的时候会先在当前作用域找。没找到。
//然后去上层作用城(自执行函数内)找,在这里找到了形参flag,初始值为true
if (flag === false) return
flag = false
setTimeout(() => {
flag = true
console.log(this.value)
}, 300);
}
})(true)
函数的节流
防抖 事件在开始执行时,如果快速触发第二次,那么第二次会取代第一次,只会执行最后一次
同样以输入框为例
<input type="text" class="inp">
const inp = document.querySelector('.inp')
inp.oninput = (function (timer) {
return function () {
clearInterval(timer)
timer = setTimeout(() => {
console.log(this.value)
}, 300);
}
})(0)