日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
一文帶你了解JavaScript函數(shù)式編程?

【稿件】

創(chuàng)新互聯(lián)為企業(yè)級(jí)客戶(hù)提高一站式互聯(lián)網(wǎng)+設(shè)計(jì)服務(wù),主要包括成都網(wǎng)站建設(shè)、成都做網(wǎng)站、app軟件開(kāi)發(fā)公司、成都微信小程序、宣傳片制作、LOGO設(shè)計(jì)等,幫助客戶(hù)快速提升營(yíng)銷(xiāo)能力和企業(yè)形象,創(chuàng)新互聯(lián)各部門(mén)都有經(jīng)驗(yàn)豐富的經(jīng)驗(yàn),可以確保每一個(gè)作品的質(zhì)量和創(chuàng)作周期,同時(shí)每年都有很多新員工加入,為我們帶來(lái)大量新的創(chuàng)意。 

前言

函數(shù)式編程在前端已經(jīng)成為了一個(gè)非常熱門(mén)的話題。在最近幾年里,我們看到非常多的應(yīng)用程序代碼庫(kù)里大量使用著函數(shù)式編程思想。

本文將略去那些晦澀難懂的概念介紹,重點(diǎn)展示在 JavaScript 中到底什么是函數(shù)式的代碼、聲明式與命令式代碼的區(qū)別、以及常見(jiàn)的函數(shù)式模型都有哪些?

一、什么是函數(shù)式編程

函數(shù)式編程是一種編程范式,主要是利用函數(shù)把運(yùn)算過(guò)程封裝起來(lái),通過(guò)組合各種函數(shù)來(lái)計(jì)算結(jié)果。函數(shù)式編程意味著你可以在更短的時(shí)間內(nèi)編寫(xiě)具有更少錯(cuò)誤的代碼。舉個(gè)簡(jiǎn)單的例子,假設(shè)我們要把字符串 functional programming is great 變成每個(gè)單詞首字母大寫(xiě),我們可以這樣實(shí)現(xiàn):

 
 
 
 
  1. var string = 'functional programming is great'; 
  2. var result = string 
  3. .split(' ') 
  4. .map(v => v.slice(0, 1).toUpperCase() + v.slice(1)) 
  5. .join(' '); 

上面的例子先用 split 把字符串轉(zhuǎn)換數(shù)組,然后再通過(guò) map 把各元素的首字母轉(zhuǎn)換成大寫(xiě),最后通過(guò) join 把數(shù)組轉(zhuǎn)換成字符串。 整個(gè)過(guò)程就是 join(map(split(str))),體現(xiàn)了函數(shù)式編程的核心思想: 通過(guò)函數(shù)對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)換。

由此我們可以得到,函數(shù)式編程有兩個(gè)基本特點(diǎn):

  • 通過(guò)函數(shù)來(lái)對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)換

  • 通過(guò)串聯(lián)多個(gè)函數(shù)來(lái)求結(jié)果

二、對(duì)比聲明式與命令式

接下來(lái)我們先介紹兩種編程范式:

  • 命令式:我們通過(guò)編寫(xiě)一條又一條指令去讓計(jì)算機(jī)執(zhí)行一些動(dòng)作,這其中一般都會(huì)涉及到很多繁雜的細(xì)節(jié)。命令式代碼中頻繁使用語(yǔ)句,來(lái)完成某個(gè)行為。比如 for、if、switch、throw 等這些語(yǔ)句。

  • 聲明式:我們通過(guò)寫(xiě)表達(dá)式的方式來(lái)聲明我們想干什么,而不是通過(guò)一步一步的指示。表達(dá)式通常是某些函數(shù)調(diào)用的復(fù)合、一些值和操作符,用來(lái)計(jì)算出結(jié)果值。

 
 
 
 
  1. //命令式 
  2. var CEOs = []; 
  3. for(var i = 0; i < companies.length; i++){ 
  4.   CEOs.push(companies[i].CEO) 
  5. //聲明式 
  6. var CEOs = companies.map(c => c.CEO); 

從上面的例子中,我們可以看到聲明式的寫(xiě)法是一個(gè)表達(dá)式,無(wú)需關(guān)心如何進(jìn)行計(jì)數(shù)器迭代,返回的數(shù)組如何收集,它指明的是做什么,而不是怎么做。函數(shù)式編程的一個(gè)明顯的好處就是這種聲明式的代碼,對(duì)于無(wú)副作用的純函數(shù),我們完全可以不考慮函數(shù)內(nèi)部是如何實(shí)現(xiàn)的,專(zhuān)注于編寫(xiě)業(yè)務(wù)代碼。

三、常見(jiàn)特性

很多時(shí)候我們?nèi)ゲ殚喓瘮?shù)式編程的相關(guān)資料,經(jīng)常會(huì)看到以下幾個(gè)特性:

無(wú)副作用

指調(diào)用函數(shù)時(shí)不會(huì)修改外部狀態(tài),即一個(gè)函數(shù)調(diào)用 n 次后依然返回同樣的結(jié)果。

 
 
 
 
  1. var a = 1; 
  2. // 含有副作用,它修改了外部變量 a 
  3. // 多次調(diào)用結(jié)果不一樣 
  4. function test1() { 
  5. a++ 
  6. return a; 
  7. // 無(wú)副作用,沒(méi)有修改外部狀態(tài) 
  8. // 多次調(diào)用結(jié)果一樣 
  9. function test2(a) { 
  10. return a + 1; 

透明引用

指一個(gè)函數(shù)只會(huì)用到傳遞給它的變量以及自己內(nèi)部創(chuàng)建的變量,不會(huì)使用到其他變量。

 
 
 
 
  1. var a = 1; 
  2. var b = 2; 
  3. // 函數(shù)內(nèi)部使用的變量并不屬于它的作用域 
  4. function test1() { 
  5. return a + b; 
  6. // 函數(shù)內(nèi)部使用的變量是顯式傳遞進(jìn)去的 
  7. function test2(a, b) { 
  8. return a + b; 

不可變變量

指的是一個(gè)變量一旦創(chuàng)建后,就不能再進(jìn)行修改,任何修改都會(huì)生成一個(gè)新的變量。使用不可變變量最大的好處是線程安全。多個(gè)線程可以同時(shí)訪問(wèn)同一個(gè)不可變變量,讓并行變得更容易實(shí)現(xiàn)。 由于 JavaScript 原生不支持不可變變量,需要通過(guò)第三方庫(kù)來(lái)實(shí)現(xiàn)。 (如 Immutable.js,Mori 等等)

 
 
 
 
  1. var obj = Immutable({ a: 1 }); 
  2. var obj2 = obj.set('a', 2); 
  3. console.log(obj); // Immutable({ a: 1 }) 
  4. console.log(obj2); // Immutable({ a: 2 }) 

函數(shù)是一等公民

我們常說(shuō)函數(shù)是JavaScript的"第一等公民",指的是函數(shù)與其他數(shù)據(jù)類(lèi)型一樣,處于平等地位,可以賦值給其他變量,也可以作為參數(shù),傳入另一個(gè)函數(shù),或者作為別的函數(shù)的返回值。下文將要介紹的閉包、高階函數(shù)、函數(shù)柯里化和函數(shù)組合都是圍繞這一特性的應(yīng)用

四、常見(jiàn)的函數(shù)式編程模型

常見(jiàn)的函數(shù)式編程模型有閉包、高階函數(shù)、函數(shù)柯里化以及函數(shù)組合,以下將一一詳細(xì)介紹:

1.閉包(Closure)

如果一個(gè)函數(shù)引用了自由變量,那么該函數(shù)就是一個(gè)閉包。何謂自由變量?自由變量是指不屬于該函數(shù)作用域的變量(所有全局變量都是自由變量,嚴(yán)格來(lái)說(shuō)引用了全局變量的函數(shù)都是閉包,但這種閉包并沒(méi)有什么用,通常情況下我們說(shuō)的閉包是指函數(shù)內(nèi)部的函數(shù))。

閉包的形成條件:

  • 存在內(nèi)、外兩層函數(shù)

  • 內(nèi)層函數(shù)對(duì)外層函數(shù)的局部變量進(jìn)行了引用

閉包的用途: 可以定義一些作用域局限的持久化變量,這些變量可以用來(lái)做緩存或者計(jì)算的中間量等

 
 
 
 
  1. // 簡(jiǎn)單的緩存工具 
  2. // 匿名函數(shù)創(chuàng)造了一個(gè)閉包 
  3. const cache = (function() { 
  4. const store = {}; 
  5.   
  6. return { 
  7.   get(key) { 
  8.     return store[key]; 
  9.   }, 
  10.   set(key, val) { 
  11.     store[key] = val; 
  12.   } 
  13. }()); 
  14. console.log(cache) //{get: ?, set: ?} 
  15. cache.set('a', 1); 
  16. cache.get('a'); // 1 

上面例子是一個(gè)簡(jiǎn)單的緩存工具的實(shí)現(xiàn),匿名函數(shù)創(chuàng)造了一個(gè)閉包,使得 store 對(duì)象 ,一直可以被引用,不會(huì)被回收。

閉包的弊端:持久化變量不會(huì)被正常釋放,持續(xù)占用內(nèi)存空間,很容易造成內(nèi)存浪費(fèi),所以一般需要一些額外手動(dòng)的清理機(jī)制。

2.高階函數(shù)

函數(shù)式編程傾向于復(fù)用一組通用的函數(shù)功能來(lái)處理數(shù)據(jù),它通過(guò)使用高階函數(shù)來(lái)實(shí)現(xiàn)。高階函數(shù)指的是一個(gè)函數(shù)以函數(shù)為參數(shù),或以函數(shù)為返回值,或者既以函數(shù)為參數(shù)又以函數(shù)為返回值。

高階函數(shù)經(jīng)常用于:

  • 抽象或隔離行為、作用,異步控制流程作為回調(diào)函數(shù),promises,monads等

  • 創(chuàng)建可以泛用于各種數(shù)據(jù)類(lèi)型的功能

  • 部分應(yīng)用于函數(shù)參數(shù)(偏函數(shù)應(yīng)用)或創(chuàng)建一個(gè)柯里化的函數(shù),用于復(fù)用或函數(shù)復(fù)合。

  • 接受一個(gè)函數(shù)列表并返回一些由這個(gè)列表中的函數(shù)組成的復(fù)合函數(shù)。

JavaScript 語(yǔ)言是原生支持高階函數(shù)的, 例如Array.prototype.map,Array.prototype.filter 和 Array.prototype.reduce 是JavaScript中內(nèi)置的一些高階函數(shù),使用高階函數(shù)會(huì)讓我們的代碼更清晰簡(jiǎn)潔。

map

map() 方法創(chuàng)建一個(gè)新數(shù)組,其結(jié)果是該數(shù)組中的每個(gè)元素都調(diào)用一個(gè)提供的函數(shù)后返回的結(jié)果。map 不會(huì)改變?cè)瓟?shù)組。

假設(shè)我們有一個(gè)包含名稱(chēng)和種類(lèi)屬性的對(duì)象數(shù)組,我們想要這個(gè)數(shù)組中所有名稱(chēng)屬性放在一個(gè)新數(shù)組中,如何實(shí)現(xiàn)呢?

 
 
 
 
  1. // 不使用高階函數(shù) 
  2. var animals = [ 
  3. { name: "Fluffykins", species: "rabbit" }, 
  4. { name: "Caro", species: "dog" }, 
  5. { name: "Hamilton", species: "dog" }, 
  6. { name: "Harold", species: "fish" }, 
  7. { name: "Ursula", species: "cat" }, 
  8. { name: "Jimmy", species: "fish" } 
  9. ]; 
  10. var names = []; 
  11. for (let i = 0; i < animals.length; i++) { 
  12. names.push(animals[i].name); 
  13. console.log(names); //["Fluffykins", "Caro", "Hamilton", "Harold", "Ursula", "Jimmy"] 
  14. // 使用高階函數(shù) 
  15. var animals = [ 
  16. { name: "Fluffykins", species: "rabbit" }, 
  17. { name: "Caro", species: "dog" }, 
  18. { name: "Hamilton", species: "dog" }, 
  19. { name: "Harold", species: "fish" }, 
  20. { name: "Ursula", species: "cat" }, 
  21. { name: "Jimmy", species: "fish" } 
  22. ]; 
  23. var names = animals.map(x=>x.name); 
  24. console.log(names); //["Fluffykins", "Caro", "Hamilton", "Harold", "Ursula", "Jimmy"] 

filter

filter() 方法會(huì)創(chuàng)建一個(gè)新數(shù)組,其中包含所有通過(guò)回調(diào)函數(shù)測(cè)試的元素。filter 為數(shù)組中的每個(gè)元素調(diào)用一次 callback 函數(shù), callback 函數(shù)返回 true 表示該元素通過(guò)測(cè)試,保留該元素,false 則不保留。filter 不會(huì)改變?cè)瓟?shù)組,它返回過(guò)濾后的新數(shù)組。

假設(shè)我們有一個(gè)包含名稱(chēng)和種類(lèi)屬性的對(duì)象數(shù)組。 我們想要?jiǎng)?chuàng)建一個(gè)只包含狗(species: "dog")的數(shù)組。如何實(shí)現(xiàn)呢?

 
 
 
 
  1. // 不使用高階函數(shù) 
  2. var animals = [ 
  3. { name: "Fluffykins", species: "rabbit" }, 
  4. { name: "Caro", species: "dog" }, 
  5. { name: "Hamilton", species: "dog" }, 
  6. { name: "Harold", species: "fish" }, 
  7. { name: "Ursula", species: "cat" }, 
  8. { name: "Jimmy", species: "fish" } 
  9. ]; 
  10. var dogs = []; 
  11. for (var i = 0; i < animals.length; i++) { 
  12. if (animals[i].species === "dog") dogs.push(animals[i]); 
  13. console.log(dogs); 
  14. // 使用高階函數(shù) 
  15. var animals = [ 
  16. { name: "Fluffykins", species: "rabbit" }, 
  17. { name: "Caro", species: "dog" }, 
  18. { name: "Hamilton", species: "dog" }, 
  19. { name: "Harold", species: "fish" }, 
  20. { name: "Ursula", species: "cat" }, 
  21. { name: "Jimmy", species: "fish" } 
  22. ]; 
  23. var dogs = animals.filter(x => x.species === "dog"); 
  24. console.log(dogs); // {name: "Caro", species: "dog"} 
  25. // { name: "Hamilton", species: "dog" } 

reduce

reduce 方法對(duì)調(diào)用數(shù)組的每個(gè)元素執(zhí)行回調(diào)函數(shù),最后生成一個(gè)單一的值并返回。 reduce 方法接受兩個(gè)參數(shù):1)reducer 函數(shù)(回調(diào)),2)一個(gè)可選的 initialValue。

假設(shè)我們要對(duì)一個(gè)數(shù)組的求和:

 
 
 
 
  1. // 不使用高階函數(shù) 
  2. const arr = [5, 7, 1, 8, 4]; 
  3. let sum = 0; 
  4. for (let i = 0; i < arr.length; i++) { 
  5. sum = sum + arr[i]; 
  6. console.log(sum);//25 
  7. // 使用高階函數(shù) 
  8. const arr = [5, 7, 1, 8, 4]; 
  9. const sum = arr.reduce((accumulator, currentValue) => accumulator + currentValue,0); 
  10. console.log(sum)//25 

我們可以通過(guò)下圖,形象生動(dòng)展示三者的區(qū)別:

3.函數(shù)柯里化

柯里化又稱(chēng)部分求值,柯里化函數(shù)會(huì)接收一些參數(shù),然后不會(huì)立即求值,而是繼續(xù)返回一個(gè)新函數(shù),將傳入的參數(shù)通過(guò)閉包的形式保存,等到被真正求值的時(shí)候,再一次性把所有傳入的參數(shù)進(jìn)行求值。

 
 
 
 
  1. // 普通函數(shù) 
  2. function add(x,y){ 
  3.   return x + y; 
  4. add(1,2); // 3 
  5. // 函數(shù)柯里化 
  6. var add = function(x) { 
  7. return function(y) { 
  8.   return x + y; 
  9. }; 
  10. }; 
  11. var increment = add(1); 
  12. increment(2);// 3 

這里我們定義了一個(gè) add 函數(shù),它接受一個(gè)參數(shù)并返回一個(gè)新的函數(shù)。調(diào)用 add 之后,返回的函數(shù)就通過(guò)閉包的方式記住了 add 的第一個(gè)參數(shù)。

4.函數(shù)組合 (Composition)

前面提到過(guò),函數(shù)式編程的一個(gè)特點(diǎn)是通過(guò)串聯(lián)函數(shù)來(lái)求值。然而,隨著串聯(lián)函數(shù)數(shù)量的增多,代碼的可讀性就會(huì)不斷下降。函數(shù)組合就是用來(lái)解決這個(gè)問(wèn)題的方法。 假設(shè)有一個(gè) compose 函數(shù),它可以接受多個(gè)函數(shù)作為參數(shù),然后返回一個(gè)新的函數(shù)。當(dāng)我們?yōu)檫@個(gè)新函數(shù)傳遞參數(shù)時(shí),該參數(shù)就會(huì)「流」過(guò)其中的函數(shù),最后返回結(jié)果。

 
 
 
 
  1. //兩個(gè)函數(shù)的組合 
  2. var compose = function(f, g) { 
  3.   return function(x) { 
  4.       return f(g(x)); 
  5.   }; 
  6. }; 
  7. //或者 
  8. var compose = (f, g) => (x => f(g(x))); 
  9. var add1 = x => x + 1; 
  10. var mul5 = x => x * 5; 
  11. compose(mul5, add1)(2);// =>15 

參考文章

  • Master the JavaScript Interview: What is Functional Programming?

  • So You Want to be a Functional Programmer

  • 理解 JavaScript 中的高階函數(shù)

  • 我所了解的函數(shù)式編程

  • MDN文檔

  • JavaScript函數(shù)式編程(一)

  • 我眼中的 JavaScript 函數(shù)式編程

  • JS函數(shù)式編程指南

作者介紹

浪里行舟,慕課網(wǎng)認(rèn)證作者,前端愛(ài)好者,立志往全棧工程師發(fā)展,從事前端一年多,目前技術(shù)棧有vue全家桶、ES6以及l(fā)ess等,樂(lè)于分享,最近一年寫(xiě)了五六十篇原創(chuàng)技術(shù)文章,得到諸多好評(píng)!

【原創(chuàng)稿件,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文作者和出處為.com】


本文題目:一文帶你了解JavaScript函數(shù)式編程?
網(wǎng)站地址:http://www.5511xx.com/article/cdspijo.html