文章目录
前言
随着前端学习的深入,高阶函数、函数柯里化、防抖和节流的概念及实现成为了我们需要掌握和了解的内容。
一、高阶函数
1. 什么是高阶函数?
如果一个函数接受另一个函数作为参数,那么我们就将该函数称为高阶函数。
2. JavaScript中常见的高阶函数
1. forEach和Map
var arr = [1, 2, 3];
arr.forEach((item, index) => {
console.log(item, index);
})
//手写forEach方法
Array.prototype.myForEach = function (callback) {
var len = this.length;
if(typeof callback !== "function") {
throw new Error("muse be function");
}
for(var i = 0; i < len; i++) {
callback.call(this, this[i], i); //this[i] 当前项,i 下标。
}
}
var arr1 = arr.map((item, index) => {
if(item === 1) {
item += 2;
}
return item;
})
//手写map方法
Array.prototype.myMap = function (callback) {
var len = this.length;
var arr = [];
if(typeof callback !== "function") {
throw new Error("muse be function");
}
for(var i = 0; i < len; i++) {
arr.push(callback.call(this, this[i], i));
}
return arr;
}
2. reduce
var arr = [1, 2, 3];
var sum = arr.reduce((pre, now, index, arr) => { //pre是上一轮循环返回的值(或初始值);now当前项;index前项下标;arr当前项所属的数组;
return pre + now;
}, 0) //0是初始值,也就是第一轮循环时pre的值,当没有设置初始值时,整体减少一轮循环,第一轮循环pre值为数组的第一项。
//手写reduce方法
Array.prototype.myReduce = function (fn, initvalue) {
val i = 0;
var len = this.length;
var pre = initvalue;
if(initvalue == undefined) { //如果没有传入初始值,第一轮循环pre值取数组的第一项,循环从下标为1的项开始。
pre = this[0];
i = 1;
}
for(i; i < len; i++) {
pre = fn.call(this, pre, this[i], i, this);
}
return pre;
}
3.filter
var arr = [1, 2, 3, 4, 5, 6, 7];
var arr1 = arr.filter((item, index) => {
return item % 2 === 0;
})
//手写filter方法
Array.prototype.myFilter = function (callback) {
var _newArray = [];
var len = this.length;
for(var i = 0; i < len; i++) {
if(callback.call(this, this[i], i)) {
if(typeof this[i] === "object") { //如果当前项是一个对象,我们需要先将其克隆,再加入到_newArray中。
_newArray.push(Object.create(this[i]));
}
_newArray.push(this[i]);
}
}
return _newArray;
}
4.编写自定义高阶函数
编写自定义高阶函数需要注意的点:
1. 保持纯函数和减少函数副作用;
2. 调用选择call还是apply;
//找出对象中符合要求的属性名
var obj = {
num1: 1,
num2: 2,
num3: 3,
num4: 4,
num5: 5,
num6: 6
}
function findProperty (obj, fn) {
var _obj = Object.create(obj);
var _propertyArray = [];
for(var item in _obj) {
if(fn.call(_obj, _obj[item], item)) {
_propertyArray.push(item);
}
}
return _propertyArray;
}
findProperty(obj, (val, key) => {
return value % 2 == 0;
})
二、函数柯里化
1.什么是函数柯里化?
函数柯里化就是把接收多个参数的函数,变换成接收一个单一参数(最初函数的第一个参数)的函数,这个函数接收余下的参数,并且返回结果。
2.柯里化的意义
2.1. 遇到不方便传入参数时
//回调
function a(val) {
console.log(val);
}
//当我们需要在Promise中的then方法中执行a方法,此时我们会发现val是a方法必传的参数,如果直接传val调用a方法的话,then方法中就不是执行的就不是一个函数了。
Promise.resolve().then(a.bind(this, 123)); //bind方法返回一个新的函数
2.2. 当写了一个方法,但是这个方法很多时候调用起来参数是固定的时候
//有个表单需要验证输入的值符不符合规定
function inputTest(reg, val) {
return reg.test(val);
}
//有个表单中有10个input框需要验证输入的是不是纯数字的
const numberTest = inputTest.bind(this, /^[0-9]*$/);
numberTest(val);
3.如何实现柯里化?
柯里化函数会接收到固定参数,然后在柯里化函数里面,返回一个新的函数,接收剩余参数。
//最简单的柯里化
function a(num1, num2) {
console.log(num1, num2);
}
function aCurry(num1) {
return function(num2){
console.log(num1, num2);
}
}
aCurry(1)(2);
//手写一个bind方法
Function.prototype.myBind = function (thisArg) { //第一项肯定是规定调用myBind方法的函数,其指向
if(typeof this !== "function"){ //这里的this谁调用的myBind方法就指向谁
throw new Error("muse be function");
}
var _self = this;
var args = Array.prototype.slice.call(arguments, 1);
return function () {
return _self.apply(thisArg, args.concat(Array.prototype.slice.call(arguments))); //concat方法用于连接两个或多个数组,并返回一个新数组
}
}
三、防抖和节流
1.防抖
防抖就是将某些高频触发的操作,变成只操作一次(也就是等用户高频事件完了,在进行事件操作)。
1.1. 为什么要做防抖?
当我们监听input框输入事件时,我们不需要客户每输入一个字母就触发一次监听,应该是客户完成一段输入后,再触发监听。
1.2. 防抖怎么做?
//手写一个防抖方法
function antiShake(fn, delay) {
vat timer = null;
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay)
}
}
2.节流
节流是指某个操作希望上一次事件完成后,再进行下一次(或者希望隔一定时间触发一次)。
2.1. 为什么要做节流?
如果我们写个加入购物车按钮,点击后按钮后,向服务器发送一个添加商品到购物车的请求。
这里如果我们采用防抖方法,如果我们一直点,那么就不会向后端发送请求。
采用节流,如果我们一直点,会第一次点击发送请求出去,然后等到请求返回后,再发送下一个请求。
2.2. 节流怎么做?
//手写一个节流方法
function throttle(fn, delay) {
var _switch = true;
if(_switch) {
setTimeout(() => {
fn.apply(this, argments);
_switch = true;
}, delay)
_switch = false;
}else {
return false;
}
}
3. 防抖和节流的相同点
防抖和节流都是为了阻止操作高频触发,从而影响性能。
4. 防抖和节流的区别
1. 防抖是使操作多次触发,只生效最后一次。适用于只需要一次触发生效的场景。
2. 节流是使操作每隔一段时间才能触发一次。适用于需要多次触发多次生效的场景。
总结
革命尚未成功,同志仍需努力。