ES6 箭頭函式 柯里化
先來看下高階函式定義:
- 接受1個或多個函式作為引數
- 返回函式型別
常規ES6箭頭函式用法:(返回值型別)const square = x => x * x;
高階寫法:
const has = p => o => o.hasOwnProperty(p);const sortBy = p =>(a, b)=> a[p]> b[p];
理解語法
ES5實現高階函式,也叫柯里化:
function add(x){returnfunction(y){return y + x;};}var addTwo = add(2);
addTwo(3);// => 5
add (10)(11);// => 21
add函式接受x,返回一個函式接受y返回y+x。如何用箭頭函式實現同樣功能呢?我們知道:
- 箭頭函式體是表示式,並且
- 箭頭函式隱式返回表示式
所以為了實現高階函式,我們可以使箭頭函式的函式體為另一個箭頭函式:
const add = x => y => y + x;// outer function: x => [inner function, uses x]// inner function: y => y + x;
這樣我們可以建立一個綁定了x的內部函式:
const add2 = add(2);// returns [inner function] where x = 2
add2(4);// returns 6: exec inner with y = 4, x = 2
add(8)(7);// 15
這個例子看起來沒什麼實際作用,但是很好的展示瞭如何在返回的函式中引用外部引數。
使用者排序例子
const has = p => o => o.hasOwnProperty(p);const sortBy = p =>(a, b)=> a[p]> b[p];
let result;
let users =[{ name:'Qian', age:27, pets :['Bao'], title :'Consultant'},{ name :'Zeynep', age:19, pets :['Civelek','Muazzam']},{ name:'Yael', age:52, title :'VP of Engineering'}];
result = users
.filter(has('pets')).sort(sortBy('age'));
上述程式碼利用了Array的sort 和 filter 方法,這兩個方法都接收一個函式引數,此處我們利用了箭頭函式的高階函式寫法返回需要的函式。對比下直接傳入函式的寫法:
result = users
.filter(x => x.hasOwnProperty('pets'))//pass Function to filter.sort((a, b)=> a.age > b.age);//pass Function to sort
高階函式寫法:
result = users
.filter(has('pets'))//pass Function to filter.sort(sortBy('age'));//pass Function to sort
優勢在哪?
- 減少程式碼重複
- 提高程式碼重用性
- 更容易閱讀的程式碼
假設我們想列出有pets和title的使用者,可以採用如下傳統寫法:
result = users
.filter(x => x.hasOwnProperty('pets')).filter(x => x.hasOwnProperty('title'))...
採用高階函式寫法:
result = users
.filter(has('pets')).filter(has('title'))...
可以明顯感受到高階寫法更容易寫和維護。
更進一步
假設想實現一個過濾器函式完成如下功能:判斷一個物件是否包含指定值的key。之前的has函式用於檢查物件key,我們需要在此基礎上加入值的檢查:
//[p]roperty, [v]alue, [o]bject:constis= p => v => o => o.hasOwnProperty(p)&& o[p]== v;// broken down:// outer: p => [inner1 function, uses p]// inner1: v => [inner2 function, uses p and v]// inner2: o => o.hasOwnProperty(p) && o[p] = v;
所以我們的新函式is做了下面三件事:
- 接收屬性名返回函式…
- 接收值返回函式…
- 接收物件,並判讀該物件是否有指定的屬性名和值,並返回boolean
下面是一個使用is函式的例子:
const titleIs =is('title');// titleIs == v => o => o.hasOwnProperty('title') && o['title'] == v;const isContractor = titleIs('Contractor');// isContractor == o => o.hasOwnProperty('contractor') && o['title'] == 'Contractor';
let contractors = users.filter(isContractor);
let developers = users.filter(titleIs('Developer'));
let user ={name:'Viola', age:50, title:'Actress', pets:['Zak']};
isEmployed(user);// true
isContractor(user);// false
關於命名習慣
下面的寫法需要你花點時間去理解其含義:const i = x => y => z => h(x)(y)
&& y[x] == z;
使用一些更明確含義的引數命名:const is = prop
=> val => obj => has(prop)(obj) && obj[prop] == val;
繼續
如果我們想進一步提供排序功能,但是僅改為降序排列,或者列出不包含某屬性的使用者,我們需要重新實現諸如 sortByDesc 和 notHas這樣的新函式嗎?答案是不需要,對於最終返回結果是boolean值的高階函式,我們可以對其進行取反包裝,如下:
//take args, pass them thru to function x, invert the result of xconst invert = x =>(...args)=>!x(...args);const noPets = invert(hasPets);
let petlessUsersOldestFirst = users
.filter(noPets).sort(invert(sortBy('age')));
結論
函數語言程式設計受到越來越多的重視,ES6的箭頭函式提供了更簡潔方便的JavaScript實現方式,如果你還沒有看到這種方法的廣泛使用,那麼可以預見在未來幾個月函數語言程式設計會伴隨ES6的普及變得更為流行。即使你不太喜歡這種方式,那麼理解高階函式也是非常有必要的。
轉自:https://cnodejs.org/topic/56a1d827cd415452622eed07