函数科里化
什么是函数科里化?
在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
通常,我们是怎么接收参数的呢;
对于一个函数,正常人的想法,一次性传入所有的参数。
那如果不定参数呢。
JavaScript提供了arguments来存储参数。
1. 什么是arguments?
arguments 是一个对应于传递给函数的参数的类数组对象
MDN JavaScript arguments
对于每一个函数function都有一个实例化对象arguments,(该对象并不能显式创建,比如new一个arguments,时不可能成功的),arguments表示函数的参数详情,是一个类数组对象。
什么是类数组对象呢?
众所周知,数组是一个特殊的对象,其结构为对应下标的位置存储对应的内容,并且有一个length属性。
那么,对于键值对,也就是对象类型的数据结构,可以转化为数组吗?
答案是:当然可以。
如何转化,这里就提出了类数组对象,类数组对象就是对象,与数组的区别在于他的形式是对象形式,下标为属性名,属性值为对应下标的数组值,为什么“类”呢?因为类数组对象也有一个属性length,表示转化为数组后其长度。
实际上,具有length属性的对象都可以被转化为数组,但是只有属性值为数字的,且属性值数字小于length的才能被正确的转化为数组,否则其对应数组值为 empty;
举个例子
1 | var fun=function(){ |
仔细观察这些参数,再结合函数使用参数,想一想callee的作用~
2. 科里化实例
介绍完了arguments,那科里化到底是什么形式呢?
接下来看一个简单的函数例子;
1 | var fun=function(){ |
大家都知道,函数中如果存在return关键字,则返回一个东西。
return也可以返回一个函数,但是返回函数并不代表执行函数,正如上面执行fun;一样,那么执行一个fun()呢?显然相当于执行fun2;只有执行fun()()时,才相当于执行了一个fun2();
既然可以多次执行,那么也可以多次传入参数。
我们可以利用这个多次传参选择性隐式执行的特点,做些什么呢?
1. 参数复用
1 | // 正常正则验证字符串 reg.test(txt) |
如果有很多地方都要校验是否有数字,其实就是需要将第一个参数reg进行复用,这样别的地方就能够直接调用hasNumber,hasLetter等函数,让参数能够复用,调用起来也更方便。
2. 提前确认
1 | var on = function(element, event, handler) { |
第二种写法,它相对一第一种写法就是自执行然后返回一个新的函数,这样其实就是提前确定了会走哪一个方法,避免每次都进行判断
3. 延迟运行
1 | Function.prototype.bind = function (context) { |
bind实现的机制就是Currying.
关于科里化性能:
- 存取arguments对象通常要比存取命名参数要慢一点
- 一些老版本的浏览器在arguments.length的实现上是相当慢的
- 使用fn.apply( … ) 和 fn.call( … )通常比直接调用fn( … ) 稍微慢点
- 创建大量嵌套作用域和闭包函数会带来花销,无论是在内存还是速度上
科里化经典面试题:
实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
答案:(实现多样,好用即可~)
1 | var add = function () { |
了解相关知识点:
Function.prototype.toString()
Array.prototype.slice.call()
Array.prototype.reduce()