一等公民
函数是一等公民: 所谓一等公民①
顾名思义身份高,JS
任何只要是值能到达的地方,函数均可以去。html
字符串是一等公民,那么函数也能够拥有字符串同样的特质java
var str = function(){return '123'} //储存变量
var array = ['123',function(){return '456'}]//作数组成员
var concatStr = '123'+function(){return '456'}() //拼接
function concatFun (str,fn){
return str + fn();
}
concatFun(123,function(){return '456'}) //作参数
return function(){return '123'} //被返回
复制代码
正向咱们上一文使用call、apply举例,高级函数
应该具有的特性:node
能够以函数
做为参数git
能够返回函数
github
这正是underscore
被普遍应用的缘由编程
体育老师上课打太极前找同窗集合点到:设计模式
学生总数10
人,报数顺序自行定义:数组
因而咱们写出了以下代码:bash
(function () {
var numberBill = [] //报数名单
for (var number = 0; number < 10; number++) {
numberBill.push('同窗 ' + number + ' 报数');
if (number == 10) console.log('没有学生了');
if (number < 10) console.log('还剩:' + (10 - number - 1) + '名学生没有报数');
}
})()
复制代码
结果:app
VM85068:6 还剩:9名学生没有报数
VM85068:6 还剩:8名学生没有报数
VM85068:6 还剩:7名学生没有报数
VM85068:6 还剩:6名学生没有报数
VM85068:6 还剩:5名学生没有报数
VM85068:6 还剩:4名学生没有报数
VM85068:6 还剩:3名学生没有报数
VM85068:6 还剩:2名学生没有报数
VM85068:6 还剩:1名学生没有报数
VM85068:6 还剩:0名学生没有报数
复制代码
这种编程方式很常见,谁都会写,咱们通常叫这种编程方式称之为命令编程
②,这个逻辑彻底在你掌握之中,你只要规定计算机在你想要的时候执行一些不一样的动做就能够了。
下文中出现的注解underscore
方法会在文章最后注解讲解,复杂的单独抽离几张讲解。
function signInPositive(number) { //正序签到
var count = 1;
return _.chain([])//①chain干什么的
.push('同窗 ' + count + ' 正常报数')
.tap(function (numberBill) { //②numberBill哪来的?
_.each(_.range(number),function(v,k){
if (count < number) numberBill.push('同窗 ' + (count++) + ' 正常报数')
console.log('还有'+(number-count)+'名同窗没报数');
})
}).value();//③
}
signInPositive(10)
复制代码
虽然咱们勉强用函数编程实现了,可是有啥好处呢?没啥好处,最起码这个实现方法没有凸显出函数编程的价值,还不如命令编程容易理解。
我记得去年摩托罗拉出了一个模块化手机,他的摄像头,电池,外壳貌似都能拆卸换配件的,函数式编程也是这样,咱们把能够抽象
的抽象
出来,再进行组合,进行模块化
。
上面的例子循环是从(0--传入的数字)
正序循环,如果我不想从0
开始呢?如果我倒序循环
、随机循环
呢?
改一下先把_.tap
内部的_each
循环去掉
function signIn(number) { //签到
return _.chain([])//①chain干什么的?见文章底部
/*.push('同窗 ' + number + ' 正常报数')*/
.tap(function (numberBill) { //②numberBill哪来的?见文章底部
numberBill.push('同窗 ' + (number+1) + ' 正常报数')
console.log(('同窗 ' + (number+1) + ' 正常报数'))
//我故意不在体内循环
}).value();//③value干啥的?见文章底部
}
复制代码
另外说明:
上文中
_.chain([])/*.push('同窗 ' + number + ' 正常报数')
复制代码
这个链式操做
加上push
是为了让你们理解_.chain
函数的做用,由于我在underscore
文档说过这样句话:
说的很明白了,咱们可使用_.chain
链式调用的同时,也支持JS
原生Array
的prototype
中的push
操做,而且知道你调用value()
这些后面讲,不要耽误你们的思路。
那么这个方法改为这样负责什么职能呢?
就是负责存储报数的同窗生成点名单,并不在意你怎么循环,我只负责保存,因此由于咱们为了灵活性
和模块化
吧内部的each
操做剔除了,因此咱们必然要在其余地方实现遍历,并且最好能支持自定义循环
...还要能保存上面方法返回的数据...
因而乎我想到了java
中的模板引擎
,好比jsp
,freemaker
等,有这种设置start
和end
以及步长
的操做,经过步长
:1
,2
,-1
,-2
循环,按照这个思路造个支持函数
的轮子,不是恰好能够解决这个问题嘛?
可是咱们别着急,若果你了解underscore
你会知道,这种东西你找它就行了!
哦?运气真好,不当心找到两个函数
咱们能够用_.range
和_.reduce
搭配使用,用_.range
假冒一个数组,搭配reduce
迭代,模拟出了一个相似模板引擎步长迭代器之类的东西。 是否是激起了你写JS模板引擎的欲望呢? --别傻了,js不须要,即使须要相似grunt
中的JST
插件或者Underscore _.Templates
也彻底够用了,如今是个公司都搞先后分离
模板引擎只适合博客小项目,或者大公司静态化了...
先写个DEMO
测试一下:
var sum = _.reduce(_.range(1,10,1), function(memo, num){ return memo + num; }, 0
这样咱们就写出了1-10的累加,连循环都没写
ps:( 我之前看到个文章:30天不使用for循环 )
复制代码
没让您失望吧,其实对于underscore
和lodash
中的几个重要函数什么防抖
、节流阀
...我想深刻开几张讲解的,正好我也深刻研究一下,毕竟好姿式
但愿你们都能用上。
function startPositive(start,end,signInFn){
return _.reduce(
_.range(start,end,1),
function(acc,n){
return acc.concat(signInFn(n));
},[])
}
var peapleArr = startPositive(0,10,signIn) //最终报数名单
复制代码
完成了
作了什么事?
咱们成功把耦合函数内部的循环抽离了,分为了两个函数, 主函数写名单数组,复函数提供喊到
方法而且拿到数组
startInverse
、startRandom
复函数提供方法便可若你需求更加复杂或者更加优雅,你能够把startPositive
也进行抽离,改变步长达到正序
、逆序
、随机
的效果。
① 几乎JS
的书籍都提到这个术语,如今java8都积极响应函数编程,可是有些人依然认为函数思想不如OO思想,评论区撕逼,管他呢,存在即合理。
② 命令编程,机器语言if else
case
控制,流程都是你每行代码进行控制.而函数编程更加自由、优雅。
chain_.chain(obj)
返回一个封装的对象. 在封装的对象上调用方法会返回封装的对象自己,
直道 value 方法调用为止.
复制代码
这个函数就是为了优雅的使用链式调用准备的,value很简单拿到最终值,毕竟链式调用的原理是返回对象自己,设计模式第一部分我就讲了
underscore
提供一个
value
返回真正的数据,而且
return
_wrapped
返回原始数据结束
tap_.tap(object, interceptor)
用 object做为参数来调用函数interceptor,而后返回object。这种方法的主要意图是做为函数链式调用 的一环, 为了对此对象执行操做并返回对象自己。
复制代码
可能有些人疑惑?为啥你的
.tap(function (numberBill) {
复制代码
numberBill
哪来的?
经过源码咱们就知道实际上是他利用回调将咱们传入的[]
返回的。
刚才已经讲了使用方法,涉及到函数编程,我会后期单独出几章,而且仿造轮子
本文github源码有部分注释,搭配看,更加清晰。
看状况百度 其实不懂得东西没那么可怕,咱们只有不断学习才能进步,不懂的东西不要百度,尽可能看看官网API,看一手资源。
本文 -- 首发github
开源交流群:147255248