【重學(xué)】函數(shù)柯里化斤斧,偏函數(shù)

大綱:

  1. 函數(shù)柯里化
  2. 偏函數(shù)
  3. 正則截取query部分
  4. ts

前置知識(shí):

  1. 函數(shù)的參數(shù)
  • 函數(shù)的 length 屬性冬殃,返回函數(shù)預(yù)期的參數(shù)個(gè)數(shù) ---------------------- (形參)
  • 函數(shù)內(nèi)的 arguments對(duì)象 包含了函數(shù)運(yùn)行時(shí)的所有參數(shù) ---------(實(shí)參)
  1. 類數(shù)組對(duì)象轉(zhuǎn)換成數(shù)組
  • [].slice.call(類似數(shù)組的對(duì)象)
  • [].slice.apply(類似數(shù)組的對(duì)象)
  • Array.prototype.slice.call(類似數(shù)組的對(duì)象)
  • Array.from()
  1. Function.prototype.apply()
  • apply的第一個(gè)參數(shù)是要綁定的對(duì)象,當(dāng)是null和undefined時(shí)募寨,指的是全局對(duì)象window
  1. concat ------------------- concat不會(huì)改變?cè)瓟?shù)組
  • concat用于多個(gè)數(shù)組的拼接族展,將新數(shù)組的成員拼接到舊數(shù)組的尾部,返回一個(gè)新數(shù)組
  • 注意:concat不會(huì)改變?cè)瓟?shù)組
  1. 偏函數(shù)和函數(shù)柯里化概念
    偏函數(shù):是固定一個(gè)或多個(gè)參數(shù)拔鹰,產(chǎn)生另一個(gè)較小元的函數(shù) n元函數(shù) => 轉(zhuǎn)換成n-x元函數(shù)
    柯里化:將多個(gè)參數(shù)函數(shù)轉(zhuǎn)化成單一參數(shù)函數(shù)------------------n元函數(shù) => 轉(zhuǎn)換成n個(gè)一元函數(shù)
  • 偏函數(shù)(partial application)partial:是部分的意思
  • 柯里化 currying
  1. rest參數(shù)
  • rest參數(shù): ...變量名 用來獲取函數(shù)的多余參數(shù)
  • ...變量名 變量名是一個(gè)數(shù)組

(1)函數(shù)柯里化

  • 函數(shù)柯里化:就是將一個(gè)多個(gè)參數(shù)的函數(shù)仪缸,轉(zhuǎn)化成一系列一個(gè)參數(shù)的函數(shù)的過程
  • 柯里化, 即 Currying 的音譯。
function x(a,b,c) {
    console.log([].slice.call(arguments))
    console.log([].slice.apply(arguments))
    console.log(Array.prototype.slice.apply(arguments))
        console.log(Array.from(arguments))
}
x(1,2,3,4,5)
x.length --------------------------- 函數(shù)形參的個(gè)數(shù) 3
x內(nèi)部的arguments.length -------------------- 函數(shù)的實(shí)參的集合 5

柯里化階段一

需求:將add(a,b,c) 轉(zhuǎn)化成 curryAdd(a)(b)(c)
缺點(diǎn):只能處理三個(gè)參數(shù)的情況列肢,不能處理任意多個(gè)參數(shù)的情況

function add(a,b,c) {
  return a+b+c
}

function curryAdd(a) {
  return function(b) {
    return function(c) {
      return a+b+c
    }
  }
}

柯里化階段二

需求:處理任意多個(gè)參數(shù)相加
缺點(diǎn): 
  1. 處理相加邏輯的代碼恰画,只是在沒有參數(shù)時(shí)才會(huì)執(zhí)行,其他部分都在處理怎么收集所有參數(shù)
  2. 所以出來相加邏輯的代碼瓷马,可以通過傳參的形式來調(diào)用拴还,執(zhí)行相加邏輯

function curryAdd() {
  let params_arr = [] //-------------------- 定義一個(gè)用于收集參數(shù)的數(shù)組
  const closure = function() { // ------------ 定義一個(gè)閉包
    const args = Array.prototype.slice.apply(arguments) //------------ 收集每次調(diào)用的參數(shù),一次可能有多個(gè)
    if (args.length) {
       params_arr = params_arr.concat(args)
       // 用concat是因?yàn)榭梢砸淮握{(diào)用欧聘,一次傳了多個(gè)參數(shù)
       // 注意concat不會(huì)改變?cè)瓟?shù)組片林,返回值是拼接過后的新數(shù)組
       return closure
     } // 如果參數(shù)存在,就收集到數(shù)組怀骤,并且返回閉包费封,繼續(xù)判斷存不存在參數(shù)
     params_arr.reduce((total, current) => total + current) // 如果參數(shù)已經(jīng)不存在了,就相加所有尺寸參數(shù)
  }
  return closure // -------------------------- 返回一個(gè)閉包
}

const fn = curryAdd()
const res = fn(1)(2)(3)(4)() // 10-------------注意需要最后一個(gè)調(diào)用一個(gè)空參數(shù)的閉包
const res2 = fn(1)(2)(3)(4, 10)() // 20

柯里化階段三

缺點(diǎn):
  1. 函數(shù)中在判斷是否傳入?yún)?shù)晒喷,沒有了再執(zhí)行相加
  2. 也就是說孝偎,最后一次一定要執(zhí)行一次空參數(shù)的回調(diào)
  3. 所以更合理的方式:就是通過函數(shù)可以接收參數(shù)的總數(shù)來判斷


function add(arr) {
  return arr.reduce((total, current) => total + current)
}

    function curryAdd(fnAdd) {
      let params_arr = [] //-------------------- 定義一個(gè)用于收集參數(shù)的數(shù)組
      const closure = function(...args) { // args是一個(gè)數(shù)組
        if (args.length) {
          params_arr = params_arr.concat(args) // 用concat是因?yàn)槊看握{(diào)用访敌,都可以傳多個(gè)參數(shù)
          return closure
        } // 如果參數(shù)存在凉敲,就收集到數(shù)組,并且返回閉包,繼續(xù)判斷存不存在參數(shù)

        // 如果參數(shù)不存在爷抓,執(zhí)行傳入的函數(shù)
        return fnAdd(params_arr)
      }
      return closure // -------------------------- 返回一個(gè)閉包
    }

const go = curryAdd(add)
const res = go(1)(2,3)(4)()
console.log(res, 'res')

柯里化階段四

    function add(x,y,z,m) {
      return x+y+z+m
    }

    function curryAdd (fnAdd) {
      let params_arr = []
      const maxLength = fnAdd.length // 形參的長(zhǎng)度
      console.log(maxLength, 'maxLength')

      const closure = function () {
        params_arr = params_arr.concat([].slice.apply(arguments))
        // 執(zhí)行一次閉包就收集一個(gè)參數(shù)势决,而不是判斷完再收集
        if (params_arr.length < maxLength) {
         // 如果參數(shù)數(shù)組中收集到的參數(shù)長(zhǎng)度 小于 函數(shù)形參的參數(shù)長(zhǎng)度,執(zhí)行閉包
          return closure
        }
        return fnAdd(...params_arr)
      }

      return closure
    }

    const go = curryAdd(add)
    const res = go(1,2)(3,4)
    console.log(res) //10

https://juejin.im/post/5c677041f265da2de25b7707

http://www.reibang.com/p/fe0d80b04129

https://juejin.im/post/5c932a556fb9a070cd56998e

https://juejin.im/post/5c619de8f265da2d8a559131







(2) 偏函數(shù)

  • 將一個(gè)或者多個(gè)參數(shù)固定到一個(gè)函數(shù)蓝撇,產(chǎn)生一個(gè)更小元的函數(shù)
function add (a, b) {
  return a + b
}
function partial (fn) {...}

const addPartial = partial(add, 1)  // ------------------ 實(shí)現(xiàn)固定一部分參數(shù)1
const res = addPartial(2) // 3 -------------------------- 只傳一部分參數(shù) 2

偏函數(shù)實(shí)現(xiàn)方式一

  • bind方法
    function add (a, b) {
      return a + b
    }
    function partial () {
      let args = Array.prototype.slice.call(arguments)
      const fn = args.shift()
      return fn.bind(this, ...args)  
     // ----------- bind方法果复,返回新的函數(shù)
     // ----------- 除了第一個(gè)參數(shù),后面的參數(shù)渤昌,是傳給fn的參數(shù)
    }
    const addPartial = partial(add, 1)
    const res = addPartial(2) // 除了固定的參數(shù)虽抄,剩下的參數(shù)在這里傳入
    console.log(res, 'res') // 3

偏函數(shù)實(shí)現(xiàn)方法二

    function add (a, b, c) {
      return a + b + c
    }

    function partial(fn) {
      let params = Array.prototype.slice.call(arguments, 1) // 拿到除取函數(shù)外的其他所有參數(shù),是一個(gè)數(shù)組

      const closure = function() {
        const currentParams =  Array.prototype.slice.call(arguments) // 每次閉包接收的參數(shù)
        params = params.concat(currentParams) // 傳入收集參數(shù)的數(shù)組中
        console.log(params)
        if ( params.length < fn.length ) { // 參數(shù)收集數(shù)組長(zhǎng)度 如果 小于add函數(shù)預(yù)期參數(shù)個(gè)數(shù)時(shí),繼續(xù)收集
          return closure
        }
        return fn.apply(null, params) // 如果等于add預(yù)期參數(shù)時(shí)独柑,停止收集參數(shù)迈窟,執(zhí)行add函數(shù)
      }
      return closure
    }
    const addPratial = partial(add, 2)
    const res = addPratial(3)(4)
    console.log(res, 'res') // 9

https://juejin.im/post/5993a7ea6fb9a0247f4f2d08

正則截取query部分

const str = 'http://www.reibang.com/u/70c8a3b8bb44?name=wu&age=20'

const slice = str.match(/([^?&=]+)=([^?&=]+)/g)
// 全局匹配
// ([^?&=]+) 除去? & = 外的一個(gè)或者多個(gè)字符

console.log(slice) // ["name=wang", "age=20"]
const str = 'http://www.baidu.com/?name=wang&age=20&sex=man#'
const res = str.match(/\?(.+)#/)[1].match(/[^&#]+=[^&#]+/g)
console.log(res)






TS

數(shù)組

數(shù)組的兩種表示方法

let list: number[] = [1, 2, 3];

let list: Array<number> = [1, 2, 3]; -------------- 數(shù)組泛型 Array<類型變量>

null 和 undefined

  • null 和 undefined 是所有類型的子類型
  • 當(dāng)指定了 --strictNullChecks標(biāo)記,null和undefined就只能賦值給void和他們各自

never

  • never類型是任何類型的子類型

類型斷言 ----------------------------- 相當(dāng)于類型轉(zhuǎn)換

  • 類型斷言有兩種形式
    • 尖括號(hào)語法
    • as語法
1. as語法 ---- 在jsx中只能使用 as

let someValue: any = "this is a string"; -------------------------- 本來 someValue 是 any類型的 變量 
let strLength: number = (someValue as string).length; ------------- 被斷言成了字符串類型

接口

  • ReadonlyArray<T> ------------ 此數(shù)組不能被修改忌栅,且類型是T類型的數(shù)組
  • Array<T> ------------------------- 數(shù)組泛型
  • readonly和const的區(qū)別
    • const 用于變量
    • readonly 用于屬性

函數(shù)類型

interface SearchFunc {
  (source: string, subString: string): boolean;   --------------- 函數(shù)類型车酣,包含參數(shù)列表和返回值
}

  • private 不能在聲明他的類的外部訪問
  • 參數(shù)屬性:通過給構(gòu)造函數(shù)參數(shù)前面添加一個(gè)訪問限制符來聲明
    • 比如:使用 private 限制一個(gè)參數(shù)屬性,會(huì)聲明并初始化一個(gè)私有成員
  • abstract:是抽象的意思

類型謂詞

  • parameterName is Type索绪,parameterName必須來自當(dāng)函數(shù)簽名里的一個(gè)參數(shù)名

typeof類型保護(hù)

類型別名

  • 類型別名會(huì)給類型取一個(gè)新名字
  • 類型別名和接口很像湖员,當(dāng)可以作用域原始值,聯(lián)合類型瑞驱,元組娘摔,和任何其他任何你需要手寫的類型
  • 類型別名不會(huì)新建一個(gè)類型,而是創(chuàng)建了一個(gè)名字钱烟,來引用那個(gè)類型
  • 同接口一個(gè)晰筛,類型別名也可以是泛型
  • 可以在類型別名的屬性中引用自己
type ------------------------------------------- 聲明一個(gè)類型別名


type Name = string;  ---------------------- 類型別名可以作用于原始類型,聯(lián)合類型拴袭,元組读第,或者其他任何需要手寫的類型
type NameResolver = () => string;  -------- 函數(shù)類型
type NameOrResolver = Name | NameResolver; ------- 聯(lián)合類型
function getName(n: NameOrResolver): Name {
    if (typeof n === 'string') { ----------------- typeof類型保護(hù)
        return n;
    }
    else {
        return n();
    }
}

type Container<T> = { value: T }; ----------- 類型別名也可以是泛型


接口 vs 類型別名

  • 接口創(chuàng)建了一個(gè)姓名字,在任何地方都可以使用拥刻,類型別名不創(chuàng)建新名字(錯(cuò)誤信息就不使用別名)
  • 類型別名不能被 extends 和 implements
  • 如果你無法通過接口來描述一個(gè)類型怜瞒,并且你需要使用聯(lián)合類型或者元組類型,通常會(huì)使用類型別名

索引類型

  • 索引類型查詢操作符般哼,索引訪問操作符
    • 索引類型查詢操作符:keyof T 的結(jié)果表示:T上已知公共屬性名的聯(lián)合
    • 索引訪問操作符:T[K] ------- 就是T中K屬性對(duì)應(yīng)的類型

映射類型

  • 從就類型中創(chuàng)建新類型的方式
    • Keys:是已經(jīng)存在的聯(lián)合類型
    • k內(nèi)部會(huì)循環(huán)keys中的屬性
    • 最后是:屬性的結(jié)果類型
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吴汪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蒸眠,更是在濱河造成了極大的恐慌漾橙,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件楞卡,死亡現(xiàn)場(chǎng)離奇詭異霜运,居然都是意外死亡脾歇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門淘捡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來藕各,“玉大人,你說我怎么就攤上這事焦除〖た觯” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵膘魄,是天一觀的道長(zhǎng)乌逐。 經(jīng)常有香客問我,道長(zhǎng)创葡,這世上最難降的妖魔是什么黔帕? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蹈丸,結(jié)果婚禮上成黄,老公的妹妹穿的比我還像新娘。我一直安慰自己逻杖,他們只是感情好奋岁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著荸百,像睡著了一般闻伶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上够话,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天蓝翰,我揣著相機(jī)與錄音,去河邊找鬼女嘲。 笑死畜份,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的欣尼。 我是一名探鬼主播爆雹,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼愕鼓!你這毒婦竟也來了钙态?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤菇晃,失蹤者是張志新(化名)和其女友劉穎册倒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磺送,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡驻子,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年屈尼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拴孤。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖甲捏,靈堂內(nèi)的尸體忽然破棺而出演熟,到底是詐尸還是另有隱情,我是刑警寧澤司顿,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布芒粹,位于F島的核電站,受9級(jí)特大地震影響大溜,放射性物質(zhì)發(fā)生泄漏化漆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一钦奋、第九天 我趴在偏房一處隱蔽的房頂上張望座云。 院中可真熱鬧,春花似錦付材、人聲如沸朦拖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽璧帝。三九已至,卻和暖如春富寿,著一層夾襖步出監(jiān)牢的瞬間睬隶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工页徐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留苏潜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓变勇,卻偏偏與公主長(zhǎng)得像窖贤,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贰锁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容