溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

ES6中的高階函數(shù):如同 a => b => c 一樣簡單

發(fā)布時(shí)間:2020-08-01 09:01:38 來源:網(wǎng)絡(luò) 閱讀:227 作者:OneAPM123 欄目:編程語言

作者:Sequoia McDowell

2016年01月16日

ES6來啦!隨著越來越多的代碼庫和思潮引領(lǐng)者開始在他們的代碼中使用ES6,以往被認(rèn)為是“僅需了解”的ES6特性變成了必需的代碼常識(shí)。這不僅僅是新的語法學(xué)習(xí) - 在許多范例中, ES6中新的語言特性可以讓在ES5中寫起來非常麻煩的表達(dá)變得更加簡單,進(jìn)而鼓勵(lì)了新表達(dá)方式的使用。下面我們將關(guān)注一個(gè)這樣簡潔表達(dá)的使用范例:ES6中的箭頭函數(shù)如何使高階函數(shù)的書寫更加簡便。

高階函數(shù)是至少具有以下兩種功能之一的函數(shù):

  1. 使用一個(gè)或多個(gè)函數(shù)作為實(shí)參

  2. 返回一個(gè)函數(shù)作為結(jié)果

本文的目的并不是說服你立即采用這種新方式,盡管筆者非常鼓勵(lì)你嘗試使用!本文旨在讓你熟悉這種表達(dá)方式,這樣當(dāng)你在遇到其他人基于ES6寫的代碼庫時(shí),不會(huì)如筆者當(dāng)初一樣看著這些陌生代碼撓頭不解。如果你在此之前需要先復(fù)習(xí)一下箭頭語法的知識(shí),請(qǐng)先查閱這篇文章。

希望你熟悉有返回值的箭頭函數(shù):

const square = x => x * x;

但是下面這兩行代碼是什么意思?

const has = p => o => o.hasOwnProperty(p);
const sortBy = p => (a, b) => a[p] > b[p];

“p 返回 o 返回 o.hasOwnProperty…”這句代碼是什么意思?我們能這樣用嗎?

理解語法

為了說明帶箭頭的高階函數(shù)的書寫規(guī)則,讓我們一起來看一個(gè)經(jīng)典示例:加法函數(shù)。在ES5中會(huì)這樣寫:

function add(x){
  return function(y){
     return y + x;
  };
}
var addTwo = add(2);
addTwo(3);          // => 5
add(10)(11);        // => 21

我們的加法函數(shù)輸入x,返回了一個(gè)輸入y返回值是y + x的函數(shù)。那我們應(yīng)該如何用箭頭函數(shù)表達(dá)這個(gè)函數(shù)呢?已知...

  1. 箭頭函數(shù)定義是一個(gè)表達(dá)式,并且

  2. 箭頭函數(shù)隱式返回單一表達(dá)式結(jié)果

那么我們所要做的就是讓另一個(gè)箭頭函數(shù)作為我們箭頭函數(shù)的函數(shù)體,因此表達(dá)方式如下:

const add = x => y => y + x;
// outer function: x => [inner function, uses x]
// inner function: y => y + x;

現(xiàn)在我們就可以通過一個(gè)與變量x相關(guān)的返回值創(chuàng)建內(nèi)部函數(shù):

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

我們所寫的加法函數(shù)并不是超級(jí)有用,但是它可以說明一個(gè)外函數(shù)如何輸入一個(gè)以x為變量的參數(shù)函數(shù),并在它返回的函數(shù)中引用此函數(shù)。

用戶分類

假如你在github上看到了一個(gè)ES6代碼庫,并且遇到了下面這樣的代碼:

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'));

這些代碼又是什么意思?我們叫它箭頭原型的排列和濾波方法,每一種方法都使用一個(gè)單功能參數(shù),但是我們會(huì)調(diào)用返回函數(shù)的函數(shù)來篩選和排序,而不是編寫表達(dá)式去做這些。

讓我們來看一看,在下列每種情況下返回函數(shù)的表達(dá)方式。

無高階函數(shù):

result = users
  .filter(x => x.hasOwnProperty('pets')) //pass Function to filter
  .sort((a, b) => a.age > b.age);        //pass Function to sort

有高階函數(shù):

result = users
  .filter(has('pets'))  //pass Function to filter
  .sort(sortBy('age')); //pass Function to sort

在每個(gè)實(shí)例中,過濾過程都是通過檢查對(duì)象是否含有名為“pets”的屬性值的函數(shù)執(zhí)行的。

為什么它是有用的?

它的有效性出于以下幾個(gè)原因:

  • 它減少了重復(fù)代碼

  • 它簡化了代碼的可重用性

  • 它提升了代碼含義的清晰度

想象一下我們只想過濾出有寵物和有職位的用戶,我們可以在其中添加另一個(gè)函數(shù):

result = users
  .filter(x => x.hasOwnProperty('pets'))
  .filter(x => x.hasOwnProperty('title'))
  ...

這里的重復(fù)只是徒增雜亂:它的簡明度沒有提升,只是寫了更多代碼妨礙視線。下面是可實(shí)現(xiàn)同樣功能的使用了has函數(shù)的代碼:

result = users
  .filter(has('pets'))
  .filter(has('title'))
  ...

這段代碼更加短小精悍且易于書寫,還可以減少打錯(cuò)字的情況。筆者同時(shí)認(rèn)為這段代碼大大增加了閱讀清晰度,一眼就能讀出代碼的含義。 
至于函數(shù)重用性,如果需要在很多地方過濾出有寵物的用戶或者有職位的用戶,你可以創(chuàng)建如下函數(shù),并按需重用:

const hasPets = has('pets');
const isEmployed = has('title');
const byAge = sortBy('age');

let workers = users.filter(isEmployed);
let petOwningWorkers = workers.filter(hasPets);
let workersByAge = workers.sort(byAge);

我們也可以使用已給出的函數(shù)來獲得單返回值,并不僅僅是用于過濾數(shù)組:

let user = {name: 'Assata', age: 68, title: 'VP of Operations'};
if(isEmployed(user)){   // true
  //do employee action
}
hasPets(user);          // false
has('age')(user);       //true

更進(jìn)一步

讓我們來寫一個(gè)能檢查對(duì)象擁有一個(gè)有固定主鍵的過濾函數(shù)。has函數(shù)可檢查主鍵,然而我們需要知道兩項(xiàng)值(主鍵和鍵值),而不是一項(xiàng),來同時(shí)檢查值。下面請(qǐng)看一種方法:

//[p]roperty, [v]alue, [o]bject:
const is = 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”的函數(shù)可執(zhí)行以下三件事:

  1. 取一個(gè)屬性名并且返回一個(gè)函數(shù),該函數(shù)……

  2. 取一個(gè)函數(shù)值返回一個(gè)函數(shù),該函數(shù)……

  3. 取一個(gè)對(duì)象,并檢測(cè)該對(duì)象是否有特定函數(shù)值的特定屬性,最終返回一個(gè)布爾值。

下面是一個(gè)使用is函數(shù)來過濾用戶的示例:

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

書寫風(fēng)格說明

看一眼下面這個(gè)函數(shù),記下你弄清楚函數(shù)意義的時(shí)間:

const i = x => y => z => h(x)(y) && y[x] == z;

現(xiàn)在請(qǐng)?jiān)倏匆幌峦δ軆H在書寫風(fēng)格中略微不同的函數(shù):

const is = prop => val => obj => has(prop)(obj) && obj[prop] == val;

可見,書寫一行越簡潔越好的函數(shù)的編碼趨勢(shì)是以犧牲可讀性為代價(jià)的。請(qǐng)克制自己這樣做的沖動(dòng)!簡短卻無意義的變量名的確看起來很漂亮,但是讓人難以理解函數(shù)的功能。起一個(gè)包含多個(gè)詞的有意義的變量名和函數(shù)名,其實(shí)是在幫你自己和同事理解函數(shù)功能。

還有一件事...

如果你想以年齡降序排序而不是升序排列,該怎么做呢?或者說查找不是雇員的用戶該怎么做呢?我們需要去寫一個(gè)新的functionssortByDesc 或者notHas程序嗎?當(dāng)然不用!我們可以將已有的返回布爾值的函數(shù)封裝起來,用一個(gè)反轉(zhuǎn)其布爾值的函數(shù)來實(shí)現(xiàn)上述功能,反之亦然。

//take args, pass them thru to function x, invert the result of x
const invert = x => (...args) => !x(...args);
const noPets = invert(hasPets);

let petlessUsersOldestFirst = users
  .filter(noPets)
  .sort(invert(sortBy('age')));

總結(jié)

函數(shù)式編程在編程界的勢(shì)頭越來越強(qiáng)勁,而ES6使得在JavaScript中采用這種編程思想更加容易。如果你在JavaScript編程過程中還沒遇到過函數(shù)式編程風(fēng)格的代碼,你很可能在接下來的幾個(gè)月里就能遇到。這意味著即便你不喜歡這種風(fēng)格,理解它的基礎(chǔ)知識(shí)也是非常重要的,有的知識(shí)在這里已經(jīng)提到過了。希望這篇文章提出的概念能夠幫你在實(shí)際遇到ES6代碼時(shí)準(zhǔn)備好前提知識(shí),更希望它能鼓勵(lì)你嘗試這種編程風(fēng)格!

OneAPM 助您輕松鎖定 .NET 應(yīng)用性能瓶頸,通過強(qiáng)大的 Trace 記錄逐層分析,直至鎖定行級(jí)問題代碼。以用戶角度展示系統(tǒng)響應(yīng)速度,以地域和瀏覽器維度統(tǒng)計(jì)用戶使用情況。想閱讀更多技術(shù)文章,請(qǐng)?jiān)L問 OneAPM 官方博客。 
本文轉(zhuǎn)自 OneAPM 官方博客 

原文鏈接:https://strongloop.com/strongblog/higher-order-functions-in-es6easy-as-a-b-c/

+


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI