首页 > 其他分享 >#yyds干货盘点#再聊JS函数柯里化

#yyds干货盘点#再聊JS函数柯里化

时间:2023-02-04 10:01:31浏览次数:40  
标签:function yyds return 函数 fishWeight addWeight JS add 柯里化

一、定义:

柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

通过一个简单的例子解释一下:

function add(a, b) {
return a + b
}

add(1, 2); // 3

将函数add转化为柯里化函数_add

function _add(a){
return function(b){
return a + b
}
}

_add(1)(2); // 3

函数add和函数_add是等价的。

_add能够处理add的所有剩余参数,因此柯里化也被称为部分求值

实际上就是把add函数的a,b两个参数变成了先用一个函数接收a然后返回一个函数去处理b参数。

现在思路应该就比较清晰了:只传递给函数一部分参数来调用,让它返回一个函数去处理剩下的参数。

二、柯里化函数的作用

1、参数复用

案例:拼接地址

按照普通思路去拼接一个地址

// 拼接地址
function getUrl(protocol, hostname, pathname) {
return `${protocol}${hostname}${pathname}`;
}

const url1 = getUrl('https://', 'www.baidu.com', '/hasa');
const url2 = getUrl('https://', 'www.zhihu.com', '/saandsa');
const url3 = getUrl('https://', 'www.segmentfault.com', '/hasak');

console.log(url1, url2, url3)

每次调用getUrl参数的时候都要重复的传入参数'https://'。

柯里化封装之后:

function curry(protocol) {
return function (hostname, pathname) {
return `${protocol}${hostname}${pathname}`;
}
}

const url_curry = curry('https://');

const url1 = url_curry('www.baidu.com', '/hasa');
const url2 = url_curry('www.zhihu.com', '/saandsa');
const url3 = url_curry('www.segmentfault.com', '/hasak');

console.log(url1, url2, url3)

很明显,经过柯里化封装之后,之后再进行地址拼接的时候,减少了参数个数,降低了代码重复率。

2、提前确认/提前返回

案例:兼容IE浏览器事件的监听方法(IE is dead

传统的方法:

/*
* @param element Object DOM元素对象
* @param type String 事件类型
* @param listener Function 事件处理函数
* @param useCapture Boolean 是否捕获
*/
var addEvent = function (element, type, listener, useCapture) {
if (window.addEventListener) {
element.addEventListener(type, function (e) {
listener.call(element, e)
}, useCapture)
} else {
element.attachEvent('on' + type, function (e) {
listener.call(element, e)
})
}
}

缺陷就是,每次对DOM元素进行事件绑定时都需要重新进行判断,其实对于事件监听网页一发布浏览器已经确定了,就可以知晓浏览器到底是需要哪一种监听方式。所以我们可以让判断只执行一次。

柯里化封装之后:

var addEvent = (function () {
if (window.addEventListener) {
return function (element, type, listener, useCapture) { // return funtion
element.addEventListener(type, function () {
listener.call(element)
}, useCapture)
}
} else {
return function (element, type, listener) {
element.attachEvent('on' + type, function () {
listener.call(element)
})
}
}
})()

addEvent(element, "click", listener)

立即执行函数,在触发多次事件也依旧只会触发一次if条件判断。

3、延迟执行

案例:钓鱼统计重量

传统的方法:

let fishWeight = 0;
const addWeight = function(weight) {
fishWeight += weight;
};

addWeight(2.3);
addWeight(6.5);
addWeight(1.2);
addWeight(2.5);

console.log(fishWeight);

每次执行addWeight方法时,都进行一次鱼的体重的加和。

柯里化封装后:

function curryWeight(fn) {
let _fishWeight = [];
return function () {
if (arguments.length === 0) {
return fn.apply(null, _fishWeight);
} else {
_fishWeight = _fishWeight.concat([...arguments]);
}
}
}

function addWeight() {
let fishWeight = 0;
for (let i = 0, len = arguments.length; i < len; i++) {
fishWeight += arguments[i];
}
return fishWeight;
}

const _addWeight = curryWeight(addWeight);
_addWeight(6.5);
_addWeight(1.2);
_addWeight(2.3);
_addWeight(2.5);
console.log(_addWeight())

在执行_addWeight方法时,并没有做鱼的体重的加和,之后在最后一次执行_addWeight()时,才做了加和。做到了延迟执行addWeight方法的效果。

-----拓展:对鱼的体重进行排序-----

function curryWeight(fn) {
let _fishWeight = [];
return function () {
if (arguments.length === 0) {
return fn.apply(null, _fishWeight);
} else {
_fishWeight = _fishWeight.concat([...arguments]);
}
}
}

function sortWeight() {
return [...arguments].sort((a, b) => a - b);
}

const _addWeight = curryWeight(sortWeight);
_addWeight(6.5);
_addWeight(1.2);
_addWeight(2.3);
_addWeight(2.5);
console.log(_addWeight())

很简单,只需要修改addWeight函数即可。

三、柯里化函数的实现

Done1:
step1:实现一个函数add(1)(2)

function add(num){
let sum = num;
return function(num){
return sum+num
}
}
console.log(add(1)(2));

step2:实现add(1)(2)(3)呢?
不能一直无限嵌套,所以,返回一个函数名,在函数内部判断是否还有参数传进来

function add(num){
let sum =num;
return adds = function (num1){

if(num1) {
sum = sum+num1;
return adds
}
return sum
}
}
console.log(add(1)(2)(3)());

step3:如果实现一个add(1,2,3)(2,1)(3)(2,1,3)呢?
因为现在每次调用传入的参数是不定长的。所以并不能直接把形参给写死。

function add() {
// 收集参数
let params = [...arguments];

const getParams = function () {
// 当传入的参数为空时,对参数数组遍历求和。
if ([...arguments].length === 0) return params.reduce((pre, next) => pre + next, 0);
// 收集参数
params.push(...arguments);
return getParams;
}

// 重复调用,直到传入参数为空
return getParams;
}
let a = add(1, 2)(2, 1)(3)();
console.log(a);

Done2:

function curry() {
let args = [...arguments];
let inner = function () {
args.push(...arguments);
return inner;
}

// 核心内容:隐式转换,调用了内部的toString
inner.toString = function () {
return args.reduce(function (pre, next) {
return pre + next;
})
}
return inner;
}

const result = curry(1)(2);
console.log(+result);

有关隐式转换
1、在JavaScript中,toString()方法和valueOf()方法都可以被改写,如果被用以操作JavaScript解析器就会自动调用。所以在柯里化函数中最后重写toString恰好能满足在收集完所有参数后再去执行。

标签:function,yyds,return,函数,fishWeight,addWeight,JS,add,柯里化
From: https://blog.51cto.com/u_11365839/6036749

相关文章

  • js之查找和过滤|2-4
    通常情况下选择器可以直接定位到我们想要的元素,但是,当我们拿到一个jQuery对象后,还可以以这个对象为基准,进行查找和过滤。最常见的查找是在某个节点的所有子节点中查找,使用​......
  • vuejs从入门到精通——单文件组件(SFC)
    单文件组件(SFC)https://cn.vuejs.org/guide/scaling-up/sfc.html一、单文件组件(SFC)是什么?Vue的单文件组件(即*.vue文件,英文Single-FileComponent,简称SFC)是一种......
  • #yyds干货盘点#【愚公系列】2023年02月 微信小程序-电商项目-使用vtabs实现商品列表页
    前言要实现商品列表页需要使用到weui的纵向选项卡(vtabs)功能,用于让用户在不同的视图中进行切换。vtabs属性名类型默认值必选描述vtabsArray[]yes数据项格......
  • vuejs从入门到精通——应用配置
    应用配置https://cn.vuejs.org/guide/essentials/application.html#mounting-the-app应用实例会暴露一个.config对象允许我们配置一些应用级的选项。例如定义一个应用级......
  • vuejs从入门到精通——多个应用实例
    多个应用实例https://cn.vuejs.org/guide/essentials/application.html#multiple-application-instances应用实例并不只限于一个。createAppAPI允许你在同一个页面中创......
  • vuejs从入门到精通——根组件
    根组件https://cn.vuejs.org/guide/essentials/application.html#the-root-component一、先创建一个vue实例每个Vue应用都是通过createApp函数创建一个新的应用实例:......
  • vuejs从入门到精通——DOM 中的根组件模板
    DOM中的根组件模板https://cn.vuejs.org/guide/essentials/application.html#the-root-component当在未采用构建流程的情况下使用Vue时,我们可以在挂载容器中直接书写......
  • Node.js学习第四天-cnblog
    Node.js学习第四天1.基本使用安装[email protected]创建最基本的web服务器constexpress=require('express')constapp=express()app.listen(80,()=>{......
  • 在Spring Boot中整合Katharsis,来快速开发JSON API的Web应用
    1简介我们进行WebAPI开发的时候,经常会使用Json格式的消息体,而Json格式非常灵活,不同的人会有不同的设计风格和实现,而JSONAPI提供了一套标准。但它并不提供直接实现。Ka......
  • JS基础知识
    1.流程控制       2.顺序流程控制if语句   3.分支流程控制  3.1分支结构        3.2if语句   3.2.1语法结构  ......