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

資訊專欄INFORMATION COLUMN

函數(shù)式編程了解一下(上)

int64 / 2111人閱讀

摘要:一直以來沒有對函數(shù)式編程有一個(gè)全面的學(xué)習(xí)和使用,或者說沒有一個(gè)深刻的思考。是不是輕松了其實(shí)函數(shù)式編程主張的就是以抽象的方式創(chuàng)建函數(shù)。后面咱們在系統(tǒng)性的學(xué)習(xí)下函數(shù)式編程。

一直以來沒有對函數(shù)式編程有一個(gè)全面的學(xué)習(xí)和使用,或者說沒有一個(gè)深刻的思考。最近看到一些博客文章,突然覺得函數(shù)式編程還是蠻有意思的。看了些書和文章。這里記載下感悟和收獲。 歡迎團(tuán)隊(duì)姜某人多多指點(diǎn)@姜少。 由于博客秉持著簡短且全面原則。遂分為上下兩篇

原文地址 Nealyang

部分簡介

### 函數(shù)式編程了解一下(上)

入門簡介

HOC簡介

函數(shù)柯里化與偏應(yīng)用

函數(shù)式編程了解一下(下)

組合與管道

函子和Monad

再回首Generator

入門簡介
函數(shù)的第一原則是要小,函數(shù)的第二原則是要更小
什么是函數(shù)式編程?為什么他重要

在理解什么是函數(shù)式編程的開始,我們先了解下什么數(shù)學(xué)中,函數(shù)具有的特性

函數(shù)必須總是接受一個(gè)參數(shù)

函數(shù)必須總是返回一個(gè)值

函數(shù)應(yīng)該依據(jù)接受到的參數(shù),而不是外部的環(huán)境運(yùn)行

對于一個(gè)指定的x,必須返回一個(gè)確定的y

所以我們說,函數(shù)式編程是一種范式,我們能夠以此創(chuàng)建僅依賴輸入就可以完成自身邏輯的函數(shù)。這保證了當(dāng)函數(shù)多次調(diào)用時(shí),依然可以返回相同的結(jié)果。因此可以產(chǎn)生可緩存的、可測試的代碼庫

引用透明

所有的函數(shù)對于相同的輸入都返回相同的結(jié)構(gòu),這一特性,我們稱之為引用透明。
比如:

let identity = (i) => {return i};

這么簡單?對,其實(shí)就是這樣,也就是說他沒有依賴任何外部變量、外部環(huán)境,只要你給我東西,我經(jīng)過一頓鼓搗,總是給你返回你所能預(yù)測的結(jié)果。

這也為我們后面的并發(fā)代碼、緩存成為可能。

命令式、聲明式和抽象

函數(shù)式編程主張聲明式編程和編寫抽象代碼。其實(shí)這個(gè)比較有意思,感覺更像是面向?qū)ο蟮木幊獭?/p>

光說不練都是扯淡。舉個(gè)栗子

  var array = [1,2,3,4,5,6];
  for(let i = 0;i

這段代碼的作用簡單明了,就是遍歷!但是你有沒有感覺這個(gè)代碼呆呆的。沒有一丁點(diǎn)的靈氣?都是我告訴你該怎么該怎么做的。我們告訴編譯器,你先去獲取下數(shù)組的長度的,然后挨個(gè)log出來。這種編碼方式,我們通常稱之為“命令式”解決方案。

而在函數(shù)式編程中,我們其實(shí)更加主張用“聲明式”解決方案

let array = [1,2,3,4,5,6];
array.forEach(item=>{console.log(item)})

簡單體會(huì)下,是不是有那么一丟丟的靈感來了?等等,你這個(gè)forEach函數(shù)哪來的嘛!對,也是自己寫的,但是不是我們通過編寫這種抽象邏輯代碼,而讓整體的業(yè)務(wù)代碼更加的清晰明了了呢?開發(fā)者是需要關(guān)心手頭上的問題就好了,只需要告訴編譯器去干嘛而不是怎么干了。是不是輕松了?

其實(shí)函數(shù)式編程主張的就是以抽象的方式創(chuàng)建函數(shù)。這些函數(shù)可以在代碼的其他部分被重用。

函數(shù)式編程的好處

好處個(gè)人不喜歡扯太多,不是因?yàn)樗麤]有好處,而是對于剛剛接觸函數(shù)式編程的哥們,上來就說好處其實(shí)是沒什么概念的,所以這里我簡單提一提,后面文章會(huì)細(xì)細(xì)說明。

純函數(shù) => 可緩存

熟悉redux的同學(xué)應(yīng)該對這個(gè)詞語都不陌生,所謂的純函數(shù),其實(shí)也就是我們說的引用透明,穩(wěn)定輸出!好處呢?可預(yù)測嘛,容易編寫測試代碼哇,可緩存嘛。什么是可緩存?可以看我之前發(fā)的文章哈,這里簡單舉個(gè)栗子

let longRunningFunction = (input)=>{
  //進(jìn)行了非常麻煩的計(jì)算,然后返回出來結(jié)果
  return output;
}

如果longRunningFunction是一個(gè)純函數(shù),引用透明。我們就可以說對于同樣的輸出,總是返回同樣的結(jié)果,所以我們?yōu)槭裁床荒軌蜻\(yùn)用一個(gè)對象將我們每一次的運(yùn)算結(jié)果存起來呢?

let longRunningFunctionResult = {1:2,2:3,3:4};
//檢查key是否存在,存在直接用,不存在再計(jì)算
longRunningFunctionResult.hasOwnProperty(input)?longRunningFunctionResult[input]:longRunningFunctionResult[input] = longRunningFunction(input)

比較直觀。不多說了哈。其實(shí)好處還有之前說到的并發(fā)。不說的這么冠冕堂皇了,啥并不并發(fā)呀,我不依賴別人的任何因素,只依據(jù)你的輸出我產(chǎn)出。你說我支持什么就是什么咯,只要你給我對的參數(shù)傳進(jìn)來就可以了。

結(jié)束語

匆匆收尾!僅作為拋磚引玉。后面咱們在系統(tǒng)性的學(xué)習(xí)下函數(shù)式編程。

高階函數(shù)(HOC)簡介 概念

JavaScript作為一門語言,將函數(shù)視為數(shù)據(jù)。允許函數(shù)代替數(shù)據(jù)傳遞是一個(gè)非常強(qiáng)大的概念。接受一個(gè)函數(shù)作為參數(shù)的函數(shù)成為高階函數(shù)(Higher-Order Function)

從數(shù)據(jù)入門HOC

JavaScript支持如下幾種數(shù)據(jù)類型:

Number

String

Boolean

Object

null

undefined

這里面想強(qiáng)調(diào)的是JavaScript將函數(shù)也同樣是為一種數(shù)據(jù)類型。當(dāng)一門語言允許將函數(shù)作為數(shù)據(jù)那樣傳遞和使用的時(shí)候,我們就稱函數(shù)為一等公民。

所以說這個(gè)就是為了強(qiáng)調(diào)說明,在JavaScript中,函數(shù)可以被賦值,作為參數(shù)傳遞,也可以被其他函數(shù)返回。

//傳遞函數(shù)
let tellType = (arg)=>{
  if(typeof arg === "function"){
    arg();
  }else{
    console.log(`this data is ${arg}`)
  }
}

let dataFn = ()=> {
  console.log("this is a Function");
}

tellType(dataFn);
//返回函數(shù)
let returnStr = ()=> String;

returnStr()("Nealyang")

//let fn = returnStr();
//fn("Nealyang");

從上我們可以看到函數(shù)可以接受另一個(gè)函數(shù)作為參數(shù),同樣,函數(shù)也可以將兩一個(gè)函數(shù)作為返回值返回。

所以高階函數(shù)就是接受函數(shù)作為參數(shù)并且/或者返回函數(shù)作為輸出的函數(shù)
HOC 到底你是干嘛的

當(dāng)我們了解到如何去創(chuàng)建并執(zhí)行一個(gè)高階函數(shù)的時(shí)候,同行我們都想去了解,他到底是干嘛的?OK,簡單的說,高階函數(shù)常用于抽象通用的問題。換句話說,高階函數(shù)就是定義抽象。簡單的說,其實(shí)就類似于命令式的編程方式,將具體的實(shí)現(xiàn)細(xì)節(jié)封裝、抽象起來,讓開發(fā)者更加的關(guān)心業(yè)務(wù)。抽象讓我們專注于預(yù)定的目標(biāo)而不是去關(guān)心底層的系統(tǒng)概念。

理解這個(gè)概念非常重要,所以下面我們將通過大量的栗子來說明

舉斤栗子
const every = (arr,fn)=>{
  let result = true;
  for(const value of arr){
    result  = result && fn(value);
  }
  return result;
}

every([NaN,NaN,4],isNaN);

const some = (arr,fn)=>{
  let result = true;
  for(const value of arr){
    result  = result || fn(value);
  }
  return result;
}
some([3,1,2],isNaN);
//這里都是低效的實(shí)現(xiàn)。這里主要是理解高階函數(shù)的概念
let sortObj = [
  {firstName:"aYang",lastName:"dNeal"},
  {firstName:"bYang",lastName:"cNeal"},
  {firstName:"cYang",lastName:"bNeal"},
  {firstName:"dYang",lastName:"aNeal"},
];

const sortBy = (property)=>{
  return (a,b) => {
    return (a[property]b[property])?1:0
  }
}

sortObj.sort(sortBy("lastName"));
//sort函數(shù)接受了被sortBy函數(shù)返回的比較函數(shù),我們再次抽象出compareFunction的邏輯,讓用戶更加關(guān)注比較,而不用去在乎怎么比較的。
HOC必然離不開閉包

上面的sortBy其實(shí)大家都應(yīng)該看到了閉包的蹤影。關(guān)于閉包的產(chǎn)生、概念這里就不啰嗦了。總之我們知道,閉包非常強(qiáng)大的原因就是它對作用域的訪問。

簡單說下閉包的三個(gè)可訪問的作用域:

在它自身聲明之內(nèi)的變量

對全局變量的訪問

對外部函數(shù)變量的訪問(*)

接著舉栗子
const forEach = (arr,fn)=>{
  for(const item of arr){
    fn(item);
  }
}
//tap接受一個(gè)value,返回一個(gè)帶有value的閉包函數(shù)
const tap = (value)=>(fn)=>{
  typeof fn === "function"?fn(value):console.log(value);
}

forEach([1,2,3,4,5],(a)=>{
  tap(a)(()=>{
    console.log(`Nealyang:${a}`)
  })
});
函數(shù)柯里化與偏應(yīng)用 函數(shù)柯里化 概念

直接看概念,柯里化是把一個(gè)多參函數(shù)轉(zhuǎn)換為一個(gè)嵌套的一元函數(shù)的過程

不理解,莫方!舉個(gè)栗子就明白了。

假設(shè)我們有一個(gè)函數(shù),add:

const add = (x,y)=>x+y;

我們調(diào)用的時(shí)候當(dāng)然就是add(1,2),沒有什么特別的。當(dāng)我們柯里化了以后呢,就是如下版本:

const addCurried = x => y => x + y;

調(diào)用的時(shí)候呢,就是這個(gè)樣子的:

addCurried(4)(4)//8

是不是非常的簡單?

說到這,我們在來回顧下,柯里化的概念:把一個(gè)多參函數(shù)轉(zhuǎn)換成一個(gè)嵌套的一元函數(shù)的過程。

如何實(shí)現(xiàn)多參函數(shù)轉(zhuǎn)為一元

上面的代碼中,我們實(shí)現(xiàn)了二元函數(shù)轉(zhuǎn)為一元函數(shù)的過程。那么對于多參我們該如何做呢?

這個(gè)是比較重要的部分,我們一步一步來實(shí)現(xiàn)

我們先來添加一個(gè)規(guī)則,最一層函數(shù)檢查,如果傳入的不是一個(gè)函數(shù)來調(diào)用curry函數(shù)則拋出錯(cuò)誤。當(dāng)如果提供了柯里化函數(shù)的所有參數(shù),則通過使用這些傳入的參數(shù)調(diào)用真正的函數(shù)。

let curry = (fn) => {
if(typeof fn !== "function"){
  throw Error("not a function");
}
return function curriedFn (...args){
  return fn.apply(null,args);
}
}

所以如上,我們就可以這么玩了

const multiply = (x,y,z) => x * y * z;
curry(multiply)(1,2,3);//6

革命還未成功,我們繼續(xù)哈~下面我們的目的就是把多參函數(shù)轉(zhuǎn)為嵌套的一元函數(shù)(重回概念)

const multiply = (x,y,z) => x * y * z;
let curry = (fn) => {
  if(typeof fn !== "function"){
    throw Error("not a function");
  }
  return function curriedFn (...args){
    if(args.length < fn.length){
      return function(){
        return curriedFn.apply(null,args.concat([].slice.call(arguments)));
      }
    }
   return fn.apply(null,args);
  }
}
curry(multiply)(1)(2)(3)

如果是初次看到,可能會(huì)有些疑惑。我們一行行來瞅瞅。

args.length < fn.length

這段代碼比價(jià)直接,就是判斷,你傳入的參數(shù)是否小于函數(shù)參數(shù)長度。

args.concat([].slice.call(arguments))

我們使用cancat函數(shù)鏈接一次傳入的一個(gè)參數(shù),并遞歸調(diào)用curriedFn。由于我們將所有的參數(shù)傳入組合并遞歸調(diào)用,最終if判斷會(huì)失效,就返回結(jié)果了。

小小實(shí)操一下

我們寫一個(gè)函數(shù)在數(shù)組內(nèi)容中查找到包含數(shù)字的項(xiàng)

let curry = (fn) => {
  if(typeof fn !== "function"){
    throw Error("not a function");
  }
  return function curriedFn (...args){
    if(args.length < fn.length){
      return function(){
        return curriedFn.apply(null,args.concat([].slice.call(arguments)));
      }
    }
   return fn.apply(null,args);
  }
}
let match = curry(function(expr,str){return str.match(expr)});

let hasNumber = match(/[0-9]+/);

let filter = curry(function(f,ary){
  return ary.filter(f)
});

filter(hasNumber)(["js","number1"]);

通過如上的例子,我想我們也應(yīng)該看出來,為什么我們需要函數(shù)的柯里化:

程序片段越小越容易被配置

盡可能的函數(shù)化

偏應(yīng)用

假設(shè)我們需要10ms后執(zhí)行某一個(gè)特定操作,我們一般的做法是

setTimeout(() => console.log("do something"),10);
setTimeout(() => console.log("do other thing"),10);

如上,我們調(diào)用函數(shù)都傳入了10,能使用curry函數(shù)把他在代碼中隱藏嗎?我擦,咱curry多牛逼!肯定不行的嘛~

因?yàn)閏urry函數(shù)應(yīng)用參數(shù)列表是從最左到最右的。由于我們是根據(jù)需要傳遞函數(shù),并將10保存在常量中,所以不能以這種方式使用curry。我們可以這么做:

const setTimeoutFunction = (time , fn) => {
  setTimeout(fn,time);
}

但是如果這樣的話,我們是不是太過于麻煩了呢?為了減少了10的傳遞,還需要多造一個(gè)包裝函數(shù)?

這時(shí)候,偏應(yīng)用就出來了!!!

簡單看下代碼實(shí)現(xiàn):

const partial = function (fn,...partialArgs){
  let args = partialArgs;
  return function(...fullArgs){
    let arg = 0;
    for(let i = 0; i console.log("this is Nealyang"));

如上大家應(yīng)該都能夠理解。這里不做過多廢話解釋了。

簡單總結(jié)的說:

所以,像map,filter我們可以輕松的使用curry函數(shù)解決問題,但是對于setTimeout這類,最合適的選擇當(dāng)然就是偏函數(shù)了。總之,我們使用curry或者partial是為了讓函數(shù)參數(shù)或者函數(shù)設(shè)置變得更加的簡單強(qiáng)大。

下節(jié)預(yù)告

上一部分說的比較淺顯基礎(chǔ),希望大家也能夠從中感受到函數(shù)式編程的精妙和靈活之處。大神請直接略過~求指正求指導(dǎo)~

下一節(jié)中,將主要介紹下,函數(shù)式編程中的組合、管道、函子以及Monad。最后我們在介紹下es6的Generator,或許我們能從最后的Generator中豁然開朗獲得到很多啟發(fā)哦~~

技術(shù)交流

nodejs 技術(shù)交流 群號:698239345

React技術(shù)棧群號:398240621

前端技術(shù)雜談群號:604953717

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

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

相關(guān)文章

  • JS函數(shù)編程 - 概念

    摘要:最近在看,順便看了一些函數(shù)式編程,然后半個(gè)國慶假期就沒有了。最開始接觸函數(shù)式編程的時(shí)候,第一個(gè)接觸的概念就是高階函數(shù),和柯里化。所以我覺得最開始學(xué)習(xí)函數(shù)式編程最好先了解一些相關(guān)概念和思想會(huì)比較好。 最近在看Typescript,順便看了一些函數(shù)式編程,然后半個(gè)國慶假期就沒有了。做個(gè)筆記,分幾個(gè)部分寫吧。 最開始接觸函數(shù)式編程的時(shí)候,第一個(gè)接觸的概念就是高階函數(shù),和柯里化。咋一看,這不就...

    Forelax 評論0 收藏0
  • JavaScript 函數(shù)編程到底是個(gè)啥

    摘要:函數(shù)是一等公民。其實(shí)閉包本身也是函數(shù)式編程的一個(gè)應(yīng)用。劣勢不能算是嚴(yán)格意義上的函數(shù)式語言,很多函數(shù)式編程的特性并沒有。 隨著大前端時(shí)代的到來,在產(chǎn)品開發(fā)過程中,前端所占業(yè)務(wù)比重越來越大、交互越來越重。傳統(tǒng)的老夫拿起JQuery就是一把梭應(yīng)付當(dāng)下重交互頁面已經(jīng)十分乏力。于是乎有了Angular,React,Vue這些現(xiàn)代框架。 但隨之而來的還有大量的新知識新名詞,如MVC,MVVM,F(xiàn)l...

    denson 評論0 收藏0
  • JavaScript 函數(shù)編程到底是個(gè)啥

    摘要:函數(shù)是一等公民。其實(shí)閉包本身也是函數(shù)式編程的一個(gè)應(yīng)用。劣勢不能算是嚴(yán)格意義上的函數(shù)式語言,很多函數(shù)式編程的特性并沒有。 隨著大前端時(shí)代的到來,在產(chǎn)品開發(fā)過程中,前端所占業(yè)務(wù)比重越來越大、交互越來越重。傳統(tǒng)的老夫拿起JQuery就是一把梭應(yīng)付當(dāng)下重交互頁面已經(jīng)十分乏力。于是乎有了Angular,React,Vue這些現(xiàn)代框架。 但隨之而來的還有大量的新知識新名詞,如MVC,MVVM,F(xiàn)l...

    Aomine 評論0 收藏0
  • [python] 初探'函數(shù)編程'

    摘要:前言繼續(xù)向下看廖大教程,看到了函數(shù)式編程這一節(jié),當(dāng)時(shí)是覺得沒啥用直接跳過了,這次準(zhǔn)備要仔細(xì)看一遍了,并記錄下一些心得。 前言 繼續(xù)向下看廖大教程,看到了函數(shù)式編程這一節(jié),當(dāng)時(shí)是覺得沒啥用直接跳過了,這次準(zhǔn)備要仔細(xì)看一遍了,并記錄下一些心得。 函數(shù)式編程 上學(xué)期有上一門叫 人工智能 的課,老師強(qiáng)行要我們學(xué)了一個(gè)叫做 prolog 的語言,哇那感覺確實(shí)難受,思維方式完全和之前學(xué)過的不一樣,...

    xcc3641 評論0 收藏0
  • 函數(shù)編程之組合

    摘要:在函數(shù)式編程的組合中,我們是從右到左執(zhí)行的,上述的例子中我們借助函數(shù)實(shí)現(xiàn)組合,當(dāng)然,我們也可以用自己的方式實(shí)現(xiàn)。小結(jié)函數(shù)式編程隨著多核的發(fā)展,開始再次出現(xiàn)在我們的視野中,有時(shí)候也會(huì)擔(dān)心過于吹捧函數(shù)式,反而落入俗套。 程序的本質(zhì)是什么?數(shù)據(jù)結(jié)構(gòu)+算法!!!我想這也是很多程序員給出的答案,我自己也認(rèn)可這一觀點(diǎn),當(dāng)我們了解了某一門編程語之后,接下來我們面對的往往是數(shù)據(jù)結(jié)構(gòu)和算法的學(xué)習(xí)。而現(xiàn)在...

    Jinkey 評論0 收藏0

發(fā)表評論

0條評論

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