国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

一文帶你了解什么是JavaScript 函數(shù)式編程?

acrazing / 1155人閱讀

摘要:前言函數(shù)式編程在前端已經(jīng)成為了一個(gè)非常熱門的話題。整個(gè)過程就是體現(xiàn)了函數(shù)式編程的核心思想通過函數(shù)對數(shù)據(jù)進(jìn)行轉(zhuǎn)換。高階函數(shù)函數(shù)式編程傾向于復(fù)用一組通用的函數(shù)功能來處理數(shù)據(jù),它通過使用高階函數(shù)來實(shí)現(xiàn)。

前言

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

本文將略去那些晦澀難懂的概念介紹,重點(diǎn)展示在 JavaScript 中到底什么是函數(shù)式的代碼、聲明式與命令式代碼的區(qū)別、以及常見的函數(shù)式模型都有哪些?想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客

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

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

var string = "functional programming is great";
var result = string
  .split(" ")
  .map(v => v.slice(0, 1).toUpperCase() + v.slice(1))
  .join(" ");

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

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

通過函數(shù)來對數(shù)據(jù)進(jìn)行轉(zhuǎn)換

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

二、對比聲明式與命令式

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

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

//命令式
var CEOs = [];
for(var i = 0; i < companies.length; i++){
    CEOs.push(companies[i].CEO)
}

//聲明式
var CEOs = companies.map(c => c.CEO);

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

三、常見特性 無副作用

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

var a = 1;
// 含有副作用,它修改了外部變量 a
// 多次調(diào)用結(jié)果不一樣
function test1() {
  a++
  return a;
}

// 無副作用,沒有修改外部狀態(tài)
// 多次調(diào)用結(jié)果一樣
function test2(a) {
  return a + 1;
}
透明引用

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

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

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

var obj = Immutable({ a: 1 });
var obj2 = obj.set("a", 2);
console.log(obj);  // Immutable({ a: 1 })
console.log(obj2); // Immutable({ a: 2 })
函數(shù)是一等公民

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

四、常見的函數(shù)式編程模型 1.閉包(Closure)

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

閉包的形成條件:

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

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

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

// 簡單的緩存工具
// 匿名函數(shù)創(chuàng)造了一個(gè)閉包
const cache = (function() {
  const store = {};
  
  return {
    get(key) {
      return store[key];
    },
    set(key, val) {
      store[key] = val;
    }
  }
}());
console.log(cache) //{get: ?, set: ?}
cache.set("a", 1);
cache.get("a");  // 1

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

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

2.高階函數(shù)

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

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

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

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

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

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

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

map

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

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

// 不使用高階函數(shù)
var animals = [
  { name: "Fluffykins", species: "rabbit" },
  { name: "Caro", species: "dog" },
  { name: "Hamilton", species: "dog" },
  { name: "Harold", species: "fish" },
  { name: "Ursula", species: "cat" },
  { name: "Jimmy", species: "fish" }
];
var names = [];
for (let i = 0; i < animals.length; i++) {
  names.push(animals[i].name);
}
console.log(names); //["Fluffykins", "Caro", "Hamilton", "Harold", "Ursula", "Jimmy"]
// 使用高階函數(shù)
var animals = [
  { name: "Fluffykins", species: "rabbit" },
  { name: "Caro", species: "dog" },
  { name: "Hamilton", species: "dog" },
  { name: "Harold", species: "fish" },
  { name: "Ursula", species: "cat" },
  { name: "Jimmy", species: "fish" }
];
var names = animals.map(x=>x.name);
console.log(names); //["Fluffykins", "Caro", "Hamilton", "Harold", "Ursula", "Jimmy"]
filter

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

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

// 不使用高階函數(shù)
var animals = [
  { name: "Fluffykins", species: "rabbit" },
  { name: "Caro", species: "dog" },
  { name: "Hamilton", species: "dog" },
  { name: "Harold", species: "fish" },
  { name: "Ursula", species: "cat" },
  { name: "Jimmy", species: "fish" }
];
var dogs = [];
for (var i = 0; i < animals.length; i++) {
  if (animals[i].species === "dog") dogs.push(animals[i]);
}
console.log(dogs); 
// 使用高階函數(shù)
var animals = [
  { name: "Fluffykins", species: "rabbit" },
  { name: "Caro", species: "dog" },
  { name: "Hamilton", species: "dog" },
  { name: "Harold", species: "fish" },
  { name: "Ursula", species: "cat" },
  { name: "Jimmy", species: "fish" }
];
var dogs = animals.filter(x => x.species === "dog");
console.log(dogs); // {name: "Caro", species: "dog"}
// { name: "Hamilton", species: "dog" }
reduce

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

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

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

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

3.函數(shù)柯里化

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

// 普通函數(shù)
function add(x,y){
    return x + y;
}
add(1,2); // 3
// 函數(shù)柯里化
var add = function(x) {
  return function(y) {
    return x + y;
  };
};
var increment = add(1);
increment(2);// 3

這里我們定義了一個(gè) add 函數(shù),它接受一個(gè)參數(shù)并返回一個(gè)新的函數(shù)。調(diào)用 add 之后,返回的函數(shù)就通過閉包的方式記住了 add 的第一個(gè)參數(shù)。那么,我們?nèi)绾蝸韺?shí)現(xiàn)一個(gè)簡易的柯里化函數(shù)呢?

function curryIt(fn) {
  // 參數(shù)fn函數(shù)的參數(shù)個(gè)數(shù)
  var n = fn.length;
  var args = [];
  return function(arg) {
    args.push(arg);
    if (args.length < n) {
      return arguments.callee; // 返回這個(gè)函數(shù)的引用
    } else {
      return fn.apply(this, args);
    }
  };
}
function add(a, b, c) {
  return [a, b, c];
}
var c = curryIt(add);
var c1 = c(1);
var c2 = c1(2);
var c3 = c2(3);
console.log(c3); //[1, 2, 3]

由此我們可以看出,柯里化是一種“預(yù)加載”函數(shù)的方法,通過傳遞較少的參數(shù),得到一個(gè)已經(jīng)記住了這些參數(shù)的新函數(shù),某種意義上講,這是一種對參數(shù)的“緩存”,是一種非常高效的編寫函數(shù)的方法!

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

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

//兩個(gè)函數(shù)的組合
var compose = function(f, g) {
    return function(x) {
        return f(g(x));
    };
};

//或者
var compose = (f, g) => (x => f(g(x)));
var add1 = x => x + 1;
var mul5 = x => x * 5;
compose(mul5, add1)(2);// =>15 

給大家推薦一個(gè)好用的BUG監(jiān)控工具Fundebug,歡迎免費(fèi)試用!

歡迎關(guān)注公眾號:前端工匠,你的成長我們一起見證!

參考文章

珠峰架構(gòu)課(強(qiáng)烈推薦)

MDN文檔

What is Functional Programming?

So You Want to be a Functional Programmer

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

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

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

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

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

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106575.html

相關(guān)文章

  • 從能做什么到如何去做,一文帶你快速掌握Python編程基礎(chǔ)與實(shí)戰(zhàn)

    摘要:本文的分享主要圍繞以下幾個(gè)方面能做什么常見應(yīng)用場景介紹如何學(xué)習(xí)語法基礎(chǔ)實(shí)戰(zhàn)面向?qū)ο缶幊虒?shí)戰(zhàn)練熟基礎(chǔ)小游戲項(xiàng)目的實(shí)現(xiàn)與實(shí)戰(zhàn)一能做什么一種編程語言往往可以應(yīng)用于多方面,有些方面比較常用,有些方面極為常用。比如表示是一個(gè)空列表。 摘要:Python語言的教程雖然隨處可見,但是忙于日常業(yè)務(wù)/學(xué)習(xí)的你或許:一直想要找個(gè)時(shí)間學(xué)一點(diǎn),但是又不知道該從何下手?本文將從Python能做什么,如何學(xué)習(xí)Py...

    BLUE 評論0 收藏0
  • 從源碼入手,一文帶你讀懂Spring AOP面向切面編程

    摘要:,,面向切面編程。,切點(diǎn),切面匹配連接點(diǎn)的點(diǎn),一般與切點(diǎn)表達(dá)式相關(guān),就是切面如何切點(diǎn)。例子中,注解就是切點(diǎn)表達(dá)式,匹配對應(yīng)的連接點(diǎn),通知,指在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動(dòng)作。,織入,將作用在的過程。因?yàn)樵创a都是英文寫的。 之前《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》詳細(xì)講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動(dòng)態(tài)代理嗎?看這篇就夠了》介紹了下...

    wawor4827 評論0 收藏0
  • 每個(gè) JavaScript 工程師都應(yīng)當(dāng)知道的 10 個(gè)面試題

    摘要:在創(chuàng)業(yè)初期,你招來的工程師必須是能夠獨(dú)當(dāng)一面的大神隊(duì)友。要評估一個(gè)應(yīng)聘者的真實(shí)水準(zhǔn),最佳方式就是結(jié)對編程。用微博的抓取消息并顯示在時(shí)間線上,就是個(gè)很好的考察應(yīng)聘者的面試項(xiàng)目。不過結(jié)對編程再好使,也沒辦法讓你完全了解一個(gè)應(yīng)聘者。 原文鏈接:10 Interview Questions Every JavaScript Developer Should Know 對大部分公司來說,招聘技...

    weij 評論0 收藏0
  • 不止微信、支付寶!一文帶你了解所有小程序平臺(tái)

    摘要:而在的全年財(cái)報(bào)也表明,微信小程序日活躍賬戶數(shù)增長迅速,用戶人均日訪問量同比增長,而中長尾小程序也占到了小程序日均總訪問量的。在小游戲中,微信已有單月流水過億的杰出小游戲作品。據(jù)不完全統(tǒng)計(jì),微信小程序已有余個(gè)入口。 showImg(https://segmentfault.com/img/remote/1460000018837984);小程序的平臺(tái)越來越多了,開發(fā)者的精力也越來越分散。...

    Mike617 評論0 收藏0
  • 泡沫股價(jià)、外賣小哥要失業(yè)了?測試員還要不要進(jìn)美團(tuán)?一文帶你了解背后真相

    摘要:美團(tuán)的目標(biāo)很明確,那就是把萬外賣小哥清理一大半,只留下三四線城市靠人工配送。現(xiàn)在的美團(tuán)以他核心的三大業(yè)務(wù)板塊,乘著大疫情時(shí)代股價(jià)飆升的東風(fēng),最高峰時(shí)期可以跟騰訊阿里這樣的互聯(lián)網(wǎng)巨頭相比較。 ...

    willin 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<