99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

Javascript 中的函數(shù)式編程

發(fā)布時(shí)間:2017-05-03 20:50  回復(fù):0  查看:2494   最后回復(fù):2017-05-03 20:50  
本文和大家分享的主要是javascript 中函數(shù)式編程相關(guān)內(nèi)容,一起來看看吧,希望對大家 學(xué)習(xí)javascript有所幫助。
  函數(shù)式編程(functional programming )或稱函數(shù)程序設(shè)計(jì),又稱泛函編程,是一種編程范型,比起命令式編程,函數(shù)式編程更加強(qiáng)調(diào)程序執(zhí)行的結(jié)果而非執(zhí)行的過程,倡導(dǎo)利用若干簡單的執(zhí)行單元讓計(jì)算結(jié)果不斷漸進(jìn),逐層推導(dǎo)復(fù)雜的運(yùn)算,而不是設(shè)計(jì)一個(gè)復(fù)雜的執(zhí)行過程。
  函數(shù)式編程,近年來一直被炒得火熱,國內(nèi)外的開發(fā)者好像都在議論和提倡這種編程范式。在眾多的函數(shù)式語言中,Javascript  無疑是最亮眼的一個(gè),越來越多的人開始學(xué)習(xí)和擁抱它,并使用它運(yùn)用函數(shù)式編程來開發(fā)實(shí)際的大型應(yīng)用,開源社區(qū)也源源不斷的誕生函數(shù)式風(fēng)格的框架和類庫( Angular / React / Redux )。
  作為 web  平臺唯一的標(biāo)準(zhǔn)通用語言, Javascript  在軟件歷史上掀起了最大的語言熱潮,擁有當(dāng)下最大的開源包管理工具( npm )的 Javascript  也從  Lisp  手中接過了維持?jǐn)?shù)十年的  最流行的函數(shù)式編程語言 ”  的名號。在 Javascript  的世界中是天然支持函數(shù)式編程的,函數(shù)式編程的基本特征有:
  ·  一等函數(shù)
  ·  閉包
  ·  高階函數(shù)
  ·  純度
  本文會以 Javascript  為例子,和大家一起來了解和學(xué)習(xí)函數(shù)式編程。
   一等函數(shù)(First Class Functions)
  一等函數(shù)這個(gè)術(shù)語最早在20 世紀(jì) 60 年代,由英國計(jì)算機(jī)科學(xué)家 Christopher Strachey   functions as first-class citizens  一文中提出的。意思是指,函數(shù)和其他一等公民(Number / String...) 一樣,擁有和它們一樣的能力和作用:
  · 函數(shù)儲存為變量
  const foo = () => {...}
  · 函數(shù)可以儲存為數(shù)據(jù)的一個(gè)元素
  const arr = [1, 2, () => {...}]
  · 函數(shù)可以作為對象的屬性值
  const obj = {name: 'xx', say: () => {}}
  · 函數(shù)可以在使用時(shí)直接創(chuàng)建出來
  1 + (() => { return 2; })()
  · 函數(shù)可以作為變量傳遞給另一個(gè)函數(shù)
  bar (name, fun) { fun(name) }
  bar('xx', (name) => { console.log(name) })
  · 函數(shù)可以被另一個(gè)函數(shù)返回
  foo() {
  return () => {...}
  }
  在函數(shù)式編程中,函數(shù)是作為基本單元,并且在函數(shù)之上建立代碼和數(shù)據(jù)的封裝,以提高應(yīng)用的重用和靈活性。支持一等函數(shù)的作用是顯而易見的,我們可以使用函數(shù)去完成大部分的功能。
   閉包(Closure)
  歷經(jīng)了 30 年,閉包終于成為了編程語言的主要特點(diǎn)。但是根據(jù)一項(xiàng)調(diào)查顯示,有關(guān)  Javascript  閉包的問題占了  23%  左右,對于相當(dāng)數(shù)量的開發(fā)者來說閉包仍然模糊而又神秘。對于閉包解釋我還是更傾向于 Kyle Simpson 的系列書 You Don’t Know JavaScript  中的解釋:
  函數(shù)在被定義時(shí)是可以訪問當(dāng)前的詞法作用域,當(dāng)函數(shù)離開作用域之外被執(zhí)行時(shí),就形成了閉包。
  簡而言之,閉包就是一個(gè)函數(shù),捕獲了作用域內(nèi)的外部綁定。來看個(gè)例子:
  function student (people) {
  return (name) => { return people[name] }
  }var someone = student({xx: {age: 20}, jackson: {age: 21}})
  someone('xx') // {age: 20}
  在執(zhí)行完 student  函數(shù)后,里面的匿名函數(shù)形成了一個(gè)閉包,閉包是可以訪問到  people  對象。閉包為 Javascript  提供了私有訪問,這讓給開發(fā)者建立數(shù)據(jù)抽象提供了極大地便利,也可以更好地書寫函數(shù)式代碼,建立更加強(qiáng)大的代碼。
  來思考一個(gè)場景,手頭上擁有一個(gè)書本的數(shù)組,數(shù)組里面包含了書本的信息,現(xiàn)在需要做的是找出把書名填充到一個(gè)數(shù)組中并且返回,我們一般都會這樣寫:
  const books = [{title: ' 人類簡史 ', author: 'zz'}, {title: ' 禪與摩托車維修藝術(shù)
  books.map((item) => { return item.title })
  我們使用了 Array.prototype.map  方法,傳入了一個(gè)匿名函數(shù),函數(shù)中  return  了書名  title 。假如需要利用閉包來進(jìn)一步抽象的話,要怎么寫呢?
  function plucker (key) {
  return  (obj) => {
  return (obj && obj[key])
  }
  }
  books.map(plucker('title'))
  我們定義了一個(gè) plucker  函數(shù),它接收一個(gè)  key  參數(shù)并返回一個(gè)匿名函數(shù),匿名函數(shù)就是一個(gè)閉包并補(bǔ)捕獲了  key  參數(shù)。在利用了閉包的情況下,我們可以傳入任意想要的書本信息(比如: plucker('author') ),這樣就提高了代碼的重用性和靈活性。當(dāng)我們對于閉包認(rèn)識足夠充分時(shí)并合理運(yùn)用到實(shí)際開發(fā)中去,將會切身體會到閉包的威力和它給我們帶來的便利。
   高階函數(shù)(Higher Order Functions)
  在數(shù)學(xué)和計(jì)算機(jī)科學(xué)中,高階函數(shù)式至少滿足下列一個(gè)條件的函數(shù):
  ·  接受一個(gè)或多個(gè)函數(shù)作為輸入
  ·  輸出一個(gè)函數(shù)
  在上述的 plucker  函數(shù)就是一個(gè)例子,還有我們熟知的  Array.prototype  相關(guān)的方法,比如  .map 、 .sort  等等都是高階函數(shù),因?yàn)樗鼈儩M足接受一個(gè)函數(shù)作為參數(shù)的條件。
  那么先來看一個(gè)一階函數(shù)的例子,定義一個(gè)函數(shù),它會將數(shù)組中4 個(gè)字母的單詞給過濾掉:
  const words = ['foo', 'bar', 'test', 'some']; const filter = words => {
  let arr = [];
  for(let i = 0, { length } = words; i < length; i++) {
  const word = word;
  if(word.length !== 4) {
  arr.push(word);
  }
  }
  return arr;
  }
  filter(words); // ['foo', 'bar']
  假如現(xiàn)在又需要過濾數(shù)組中,以 ‘b’  字母開頭的單詞?那么再定義一個(gè)函數(shù):
  const startWith = words => {
  let arr = [];
  for(let i = 0, { length } = arr; i < length; i++) {
  const word = word;
  if(word.indexOf('b') !== 0) {
  arr.push(word);
  }
  }
  return arr;
  }
  filter(words); // ['foo', 'test', 'some']
  根據(jù)上面兩個(gè)函數(shù)的對比來看,其實(shí)主要代碼的邏輯都是相似的,先遍歷數(shù)組再進(jìn)行條件判斷,最后 push 到數(shù)組中。其實(shí),遍歷和過濾都可以抽象出來,可以方便其他的類似函數(shù)去調(diào)用,畢竟在數(shù)組中根據(jù)條件過濾是很常見的需求。
  const reduce = (reducer, init, arr) => {
  let acc = init;
  for(let i = 0,{ length } = arr; i < length; i++) {
  acc = reducer(acc, arr);
  }
  return acc;
  }
  reduce((acc, curr) => acc + curr, 0, [1, 2, 3]);    // 6
  如果使用過 Underscore  庫的話,就會發(fā)現(xiàn)  reduce  和  Underscore.reduce  作用是一樣的,實(shí)現(xiàn)的是累計(jì)的功能。 reduce  接受了  3 個(gè)參數(shù): ruducer  函數(shù)、累計(jì)的初始值和一個(gè)數(shù)組,遍歷時(shí)將每個(gè)數(shù)組元素作為  reducer  的參數(shù)傳入,返回值又賦值給累計(jì)變量  init ,遍歷完成時(shí)也就完成了累計(jì)的功能。
  現(xiàn)在如果將 rudece  應(yīng)用到第一個(gè)需求上(過濾四個(gè)字母的單詞):
  const func = (fn ,arr) => {
  return reduce((acc, curr) => fn(curr) ? acc.concat([curr]) : acc, [], arr)
  }console.log(func(word => word.length !== 4, words)); // ["foo", "bar"]
  可以發(fā)現(xiàn),將公共代碼抽象出來之后,filter  的函數(shù)實(shí)現(xiàn)非常簡潔,只需傳入不同的條件函數(shù),就能為我們?nèi)ヌ幚矸细鞣N條件的數(shù)據(jù)。高階函數(shù)可以用來實(shí)現(xiàn)函數(shù)的多態(tài)性,并且相對于一階函數(shù),高階函數(shù)的復(fù)用性和靈活性更好。
   純度(Purity)
  函數(shù)式編程不僅僅只關(guān)心函數(shù),也是思考如何盡量地降低軟件復(fù)雜性的一種方式。在一些函數(shù)式編程語言中,純度是被強(qiáng)制執(zhí)行的,不允許使用有副作用的表達(dá)式。但是在 Javascript  中,純度必須通過管理區(qū)實(shí)現(xiàn),并且非常容易在偶然間創(chuàng)建和使用非純函數(shù)。
  一個(gè)純函數(shù)需要滿足以下三個(gè)條件:
  ·  函數(shù)結(jié)果只能通過參數(shù)來計(jì)算得出
  ·  不能依賴于能被外部操作改變的數(shù)據(jù)
  ·  不能改變外部狀態(tài)
  根據(jù)這上述條件來看,在 Javascript  的世界中去維持絕對純凈是不可能的,因?yàn)槿鄙倭舜蠖鄶?shù)函數(shù)式語言中使用的高效、不變的數(shù)據(jù)結(jié)構(gòu)。我們知道在  Javascript  擁有能力去 freeze()  對象,但是只能對接對象的頂級屬性,這就意味著一個(gè)嵌套對象下的屬性是仍然能夠被更改的。
  var obj = Object.freeze({
  foo: 'hello',
  bar: {
  text: 'world'
  }
  })
  obj.foo = 'goodbye';console.log(obj.foo); // hello
  obj.bar.text = 'goobye';console.log(obj.bar.text); // goodbye
  在 ES6  中新增的  const  關(guān)鍵字,使用  const  可以定義一個(gè)不能夠被重新賦值為不同的值,但是一個(gè)  const  對象的屬性還是可變的。
  const obj = 'hello';
  obj = 'goodbye';    // Uncaught TypeError: Assignment to constant variable.
  const obj = {
  foo: 'hello',
  bar: 'world'
  }
  obj.foo = 'goodbye';
  console.log(obj);     // {foo: 'goodbye', bar: 'world'}
  在 Javascrpt  中實(shí)現(xiàn)綜合不變性還有很長的路要走。換句話來說,雖然不能夠保證絕對的純凈,但是我們可以將純凈的部分抽離出來,將變化的影響降到最低,使得代碼變得更加通用和容易測試。
   總結(jié):
  ·  函數(shù)式編程是支持一等函數(shù)的,函數(shù)具有其他數(shù)據(jù)類型相同的功能
  ·  函數(shù)式編程中使用閉包來進(jìn)行數(shù)據(jù)的封裝
  ·  使用高階函數(shù)來建立代碼的抽象,使代碼更加靈活通用
  ·  盡量抽離純函數(shù)來保持代碼的可測性和通用性
來源: 稀土掘金

您還未登錄,請先登錄

熱門帖子

最新帖子

?