栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > Web开发 > JavaScript

柯里化技术分享(后续更新...)

JavaScript 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

柯里化技术分享(后续更新...)

一、柯里化介绍

柯里化其实是为实现多参函数提供了一个递归降解的实现思路— —把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术

简单理解就是:一个把具有较多参数 的函数转换成具有较少参数函数的过程 。如图:

此图来源于网上

二、简单案例说明

  1. 问题:求长方体的体积,写一函数。
// 一般
function volume(l,w,h) {
    return l * w * h;
}
const aCylinder = volume(100,20,90) // 180000

那么从上面柯里化的概念,我们是不是也可以得出这样的写法:

function volume(l) {
    return (w) => {
 return (h) => {
     return l * w * h
 }
    }
}
const aCylinder = volume(100)(20)(90) // 180000

【xiao案例】

通过上面的简单案例,大家对柯里化函数有什么理解?…待

那么,大家有想过一个问题么?如果有一百个参数呢?难道要写一百次?有没有一种方法可以简单的帮我们实现柯里化?
运行案例

function curry(fn) {
  var outerArgs = Array.prototype.slice.call(arguments, 1); // 用来接收参数,除了fu之外的参数存进outerArgs
  
  return function() {
    var innerArgs = Array.prototype.slice.call(arguments),
      finalArgs = outerArgs.concat(innerArgs); // 收集传入的参数,进行缓存

    return fn.apply(null, finalArgs);
  };
}

const say = (name, prefix, greeting) => `${greeting}, ${prefix} ${name}!`;

const curriedSay = curry(say);
curriedSay('Tom', 'Mr', 'Hello'); // "Hello, Mr Tom!"
curry(say,'Tom', 'Mr')('Hello');  // "Hello, Mr Tom!"

额外加入例子

【项目场景中的应用】
讲到这,大家能举例出在在项目中有哪些柯里化的应用么?…待

axios 案例

例:监听事件 EG:

function nodeListen(node, eventName){
    return function(fn){
 node.addEventListener(eventName, function(){
     fn.apply(this, Array.prototype.slice.call(arguments));
 }, false);
    }
}

var bodyClickListen = nodeListen(document.body, 'click');
bodyClickListen(function(){
    console.log('first listen');
});

bodyClickListen(function(){
    console.log('second listen');
});
// 使用柯里化,优化监听DOM节点事件。addEventListener三个参数不用每次都写。

三、柯里化使用场景

  • 参数复用

固定不变的参数,实现参数复用,比如递归用法。

  • 延迟执行

通过bind方法

// bind 方法和以上实现的 currying 方法,在功能上有极大的相似,在实现上也几乎差不多。
// 可能唯一的不同就是 bind 方法需要强制绑定 context,也就是 bind 的第一个参数会作为原函数运行时的 this 指向。而 currying 不需要此参数。所以使用 currying 或者 bind 只是一个取舍问题。

  
  Function.prototype.myBind = function(oThis) {
      if(typeof this !== 'function') {
   return;
      }
      var self = this,
   args = Array.prototype.slice.call(arguments, 1);
      return function() {
   return self.apply(oThis, args.concat(Array.prototype.slice.call(arguments)));
      }
  }
  function foo() {
      console.log(this.a);
  }
  var obj = { a: 2 };
  var bar = foo.myBind(obj);
  bar();      // 2

箭头函数

 handleonClick(data))} />
// 箭头函数能够实现延迟执行,同时也不像 bind 方法必需指定 context。可能唯一需要顾虑的就是在 react 中,会有人反对在 jsx 标签内写箭头函数,这样子容易导致直接在 jsx 标签内写业务逻辑。

通过currying


  • 性能对比

ops/sec:以每秒钟执行测试代码的次数

通过jsPerf(js基准测试)测试四种方式的性能,结果为:

箭头函数 > bind > currying > trueCurrying 。

currying 函数相比 bind 函数,其原理相似,但是性能相差巨大,其原因是 bind 由浏览器实现,运行效率有加成。

从这个结果看 Currying 性能无疑是最差的,但是另一方面就算最差的 trueCurrying,而 trueCurrying 方法中实现的自动 Currying 化,是另外三个方法所不具备的。

四、到底需不需要柯里化

  • 为什么需要柯里化

1.为了多参函数复用性

2.为函数式编程而生

例如:纯函数、compose、container等等事物,也需要用到Currying。

  • 为什么不需要柯里化

1.柯里化的一些特性也有其他解决方案,比如提前绑定参数,如箭头函数,bind等。
2. 使用柯里化等函数式特性有额外的性能开销。

a. 存取arguments对象通常要比存取命名参数要慢一点.

b. 一些老版本的浏览器在arguments.length的实现上是相当慢的.

c. 创建大量嵌套作用域和闭包函数会带来花销,无论是在内存还是速度上.

五、问题探讨

  1. 理解以下函数
let curry = function(fn) {
    var judge = function(...args) {
 if (Boolean(args[args.length - 1])===false) {
     return fn(args);//three(null)就到这里了
 } else {
     return function(...arg) { //one和two和three都是这个函数
  return judge(...args, ...arg);
     }
 }
    }
    return judge;
}

testCurry = (args)=>{
 args.pop();//去掉最后一个参数null
 if(args.length<1){
     return;
 }
 let sum = args.reduce((s,n)=>{
     return s+n;
 },0);
 console.log('参数',args);
 console.log('sum',sum);
 return sum;
    };
    
onClick =()=>{
 console.log('执行了这里 OnClick');
 let one = this.curry(this.testCurry)(1);
 let two = one(2)(3)(4)(5);
 let three = two(6,6,6,6);
 three(null);
    };
 // 函数理解(借鉴去理解文档第二个例子)   
judge并没有立即执行,而是在(...arg)=>judge(...args,...arg);方法被调用时才被执行
这个curry后的函数只有在传入的最后一个参数可以被转换为false的时候才开始执行,它存参数的方法也很简单
1,判断如果最后一个参数是否可以是false
2,是的话就把所有保存的参数放到fn里执行,结束
3,否则,返回一个新的匿名函数,这个函数把所有传入参数保存在arg数组中,而这个匿名函数被执行后,就把以前收到的参数数组和当前的参数数组合并后,放到前面说的逻辑中,在judge函数里判断,重复第1步

六、推荐借鉴资料

  • 【JS函数式程序编程】
  • 【参考文章】
  • 【柯里化与反柯里化】
  • 【bind 函数的实现原理】
  • 【高阶函数应用】
  • 【ramda】
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/246000.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号