一等公民
函式是一等公民:
所謂一等公民①
顧名思義身份高,JS
任何只要是值能到達的地方,函式都可以去。
字串是一等公民,那麼函式也可以擁有字串一樣的特質
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舉例,高階函式
應該具備的特性:
-
可以以
函式
作為引數 -
可以返回
函式
這正是underscore
被廣泛應用的原因
操場報數遊戲
體育老師上課打太極前找同學集合點到:
學生總數10
人,報數順序自行定義:
於是我們寫出瞭如下程式碼:
(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) + '名學生沒有報數');
}
})()
複製程式碼
結果:
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
控制,流程都是你每行程式碼進行控制.而函式程式設計更加自由、優雅。
文中出現的underscore函式
- _.chain
chain_.chain(obj)
返回一個封裝的物件. 在封裝的物件上呼叫方法會返回封裝的物件本身,
直道 value 方法呼叫為止.
複製程式碼
這個函式就是為了優雅的使用鏈式呼叫準備的,value很簡單拿到最終值,畢竟鏈式呼叫的原理是返回物件本身,設計模式第一部分我就講了
粗略通過原始碼我們知道underscore
提供一個value
返回真正的資料,並且return
_wrapped
返回原始資料結束
- _.tap
tap_.tap(object, interceptor)
用 object作為引數來呼叫函式interceptor,然後返回object。這種方法的主要意圖是作為函式鏈式呼叫 的一環, 為了對此物件執行操作並返回物件本身。
複製程式碼
可能有些人疑惑?為啥你的
.tap(function (numberBill) {
複製程式碼
numberBill
哪來的?
通過原始碼我們就知道其實是他利用回撥將我們傳入的[]
返回的。
- _.reduce
剛才已經講了使用方法,涉及到函式程式設計,我會後期單獨出幾章,並且仿造輪子
本文github原始碼有部分註釋,搭配看,更加清晰。
-
看情況百度 其實不懂得東西沒那麼可怕,我們只有不斷學習才能進步,不懂的東西不要百度,儘量看看官網API,看一手資源。
-
本文 -- 首發github
-
開源交流群:147255248