人类高质量JS函数柯里化
一. 速识概念🚀:
🌈🌈🌈你好呀,最近还好吗?JS函数柯里化是比较常见也是比较重要的内容。基础并不难理解,下面带你快速了解并使用js函数柯里化~ 芜湖,起飞 🛫
百度百科对柯里化的定义为:在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。概念枯燥难懂,直接看下面的例子。
比如有个add函数,计算两个参数相加的值,一般我们这样写:
function add(a, b) {
console.log(a + b);
}
add(1, 2);
而函数柯里化就是将add函数改为调用一次函数只接受一个参数,如下:
function curryAdd(a) {
return function (b) {
console.log(a + b);
};
}
curryAdd(1)(2);
它们的返回结果都是一样的,都是3,如下:
函数柯里化利用了闭包的效果,引用的变量不会被垃圾回收机制回收,对闭包不熟悉的可以看我这篇文章👉速识闭包:。那为何要大费周章的把函数柯里化呢?它的优缺点如下:
优点:
1.当存在大量相同参数时,参数复用。
2.提前确认,避免每次都重复判断。
3.延迟计算/运行。
缺点:
使用柯里化让程序具有了更多的自由度,但柯里化用到了arguments对象、递归、闭包等,频繁使用会给性能带来影响。所以视情况使用。
下面将详细说明其优点的常用写法。
二.参数复用🚊:
比如我有如下需求,调用一个函数,将输出国家、职业、姓名:
function who(country, occupation, name) {
console.log(`我来自${country},职业是${occupation},我叫${name}。`);
}
who("中国", "前端开发", "张三");
who("中国", "前端开发", "李四");
who("中国", "前端开发", "王五");
有一个问题,就是他们都是来自中国,职业都是前端开发,只有名字不一样。但是每次调用函数都要声明,如果有很多个人都这样写岂不是很麻烦啰嗦,所以我们可以柯里化后简便写法:
function curryWho(country) {
return function (occupation) {
return function (name) {
console.log(`我来自${country},职业是${occupation},我叫${name}。`);
};
};
}
var myName = curryWho("中国")("前端开发");
myName("张三");
myName("李四");
myName("王五");
一样的结果,但是简便了许多,参数能复用,不用每次都传递:
三.简单封装🚤:
我们可以简单封装一个函数,可以把一个普通函数传入,返回一个柯里化函数:
function curry(fn) {
// 获取传入函数的参数长度
let len = fn.length;
// 返回一个函数
return function temp() {
// 获取当前已得到参数
let args = [...arguments];
// 如果当前获取参数已经大于等于len
if (args.length >= len) {
//执行传入函数
return fn(...args);
} else {
// 否则继续返回函数,同时把当前参数传入
return function () {
return temp(...args, ...arguments);
};
}
};
}
封装完毕,就拿第二大点那个函数测试下:
function who(country, occupation, name) {
console.log(`我来自${country},职业是${occupation},我叫${name}。`);
}
var r = curry(who);
r("a")("b")("c");
柯里化传参数后照样运行:
延迟执行:
你看上面那个例子,如果我没有传入三个参数是不会执行的:
var r = curry(who);
r("a");
r("b")("c");
// 只有它会执行
r("d")("e")("f");
四.提前确认🚁:
比如在js中我们使用 addEventListener 来给元素绑定事件,然而在低版本的 ie 浏览器中只能使用 attachEvent ,这样我们在不确定何种浏览器运行情况下可以提前写一个函数在js一开始就执行,判断是否可以使用 addEventListener ,否则使用 attachEvent 。这样一来只用在开始的时候判断一次,不用后面每次都用到addEvenListener时都判断一次是否可用,浪费性能。
// 自创建一个whichEvent函数
const whichEvent = (function () {
// 如果存在 addEventListener
if (window.addEventListener) {
// 返回一个函数 element为元素,type为事件类型,listener为执行函数,useCapture为是否为捕获流
return function (element, type, handler, useCapture) {
element.addEventListener(
type,
function (e) {
// 执行传入的执行函数,同时改变this指向
handler.call(element, e);
},
useCapture
);
};
// 如果浏览器版本低 ,使用 attachEvent
} else if (window.attachEvent) {
// 它只有三个参数,element为元素,type为事件类型,handler为执行函数
return function (element, type, handler) {
element.attachEvent("on" + type, function (e) {
handler.call(element, e);
});
};
}
})();
使用下whichEvent看看,如点击按钮有输出:
<button>test</button>
---------。。。。。略
var btn = document.querySelector("button");
whichEvent(btn, "click", function () {
console.log("北极光之夜。666666");
});
五.扩展面试题🚗:
柯里化函数是面试常考的,下面分享一道经典的面试题。
实现一个 add 函数,它能实现 add(1,2,3)=6 ; add(1,2)(3)=6 ; add(1)(2)(3)(4)=10 … 参数传入形式与个数不确认,返回参数相加的值。
function curryAdd() {
// 定义args ,收集当前参数 , 将arguments变为数组 ,两种方法如下
var args = [...arguments];
// var args = Array.prototype.slice.call(arguments);
// 因为不确定参数个数,所以定义要返回的函数
var temp = function () {
// 把参数持续放到数组存储
args.push(...arguments);
// // 不确定参数个数,继续返回当前函数即可
return temp;
};
// 巧妙点,重写toString方法返回计算结果。详细 看下面解释。
temp.toString = function () {
// 利用 reduce方法计算args数组相加的值
return args.reduce((a, b) => a + b);
};
return temp;
}
上面利用 temp.toString = function () { 。。。} 重写toString方法返回计算结果。这是为什么呢,那是因为当你 console.log(‘ ’) 里面为一个函数时,它会调用原型上的toString方法把函数隐式转换为字符串输出显示。这样一来,我们可以重写toString方法,让它返回参数计算结果。
测试一下:
console.log(curryAdd(1));
console.log(curryAdd(1, 2, 3));
console.log(curryAdd(1, 2)(3));
console.log(curryAdd(1)(2)(3)(4));
console.log(curryAdd(1)(2, 2, 1)(3)(4));
六.总结🛬:
上面就是js函数柯里化的全部内容啦~ 总而言之,柯里化(Currying)就是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数。它的优点为:当存在大量相同参数时,参数复用。提前确认,避免每次都重复判断。延迟计算/运行。缺点:使用柯里化让程序具有了更多的自由度,但柯里化用到了arguments对象、递归、闭包等,频繁使用会给性能带来影响。所以,可以结合实际场景使用柯里化函数。
那么。下次见啦~
- 点赞
- 收藏
- 关注作者
评论(0)