1. 程式人生 > >ES6 箭頭函式 柯里化

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