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

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

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
三言兩語說透柯里化和反柯里化

JavaScript中的柯里化(Currying)和反柯里化(Uncurrying)是兩種很有用的技術(shù),可以幫助我們寫出更加優(yōu)雅、泛用的函數(shù)。本文將首先介紹柯里化和反柯里化的概念、實現(xiàn)原理和應(yīng)用場景,通過大量的代碼示例幫助讀者深入理解這兩種技術(shù)的用途。

JavaScript中的柯里化

概念

柯里化(Currying)是把接受多個參數(shù)的函數(shù)變換成接受一個單一參數(shù)(最初函數(shù)的第一個參數(shù))的函數(shù),并且返回接受余下的參數(shù)且返回結(jié)果的新函數(shù)的技術(shù)。這個技術(shù)由數(shù)學(xué)家Haskell Curry命名。

簡單來說,柯里化可以將使用多個參數(shù)的函數(shù)轉(zhuǎn)換成一系列使用一個參數(shù)的函數(shù)。例如:

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

// 柯里化后
function curriedAdd(a) {
  return function(b) {
    return a + b;
  }
}

實現(xiàn)原理

實現(xiàn)柯里化的關(guān)鍵是通過閉包保存函數(shù)參數(shù)。以下是柯里化函數(shù)的一般模式:

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function(...args2) {
        return curried.apply(this, args.concat(args2));
      }
    }
  }
}

curry函數(shù)接受一個fn函數(shù)為參數(shù),返回一個curried函數(shù)。curried函數(shù)檢查接收的參數(shù)個數(shù)args.length是否滿足fn函數(shù)需要的參數(shù)個數(shù)fn.length。如果滿足,則直接調(diào)用fn函數(shù);如果不滿足,則繼續(xù)返回curried函數(shù)等待接收剩余參數(shù)。

這樣通過閉包保存每次收到的參數(shù),直到參數(shù)的總數(shù)達(dá)到fn需要的參數(shù)個數(shù),然后將保存的參數(shù)全部 apply 給 fn執(zhí)行。

利用這個模式可以輕松將普通函數(shù)柯里化:

// 普通函數(shù)
function add(a, b) {
  return a + b;
} 

// 柯里化后
let curriedAdd = curry(add); 
curriedAdd(1)(2); // 3

應(yīng)用場景

參數(shù)復(fù)用

柯里化可以讓我們輕松復(fù)用參數(shù)。例如:

function discounts(price, discount) {
  return price * discount;
}

// 柯里化后
const tenPercentDiscount = discounts(0.1); 
tenPercentDiscount(500); // 50
tenPercentDiscount(200); // 20

提前返回函數(shù)副本

有時我們需要提前返回函數(shù)的副本給其他模塊使用,這時可以用柯里化。

// 模塊A
function ajax(type, url, data) {
  // 發(fā)送ajax請求
}

// 柯里化后
export const getJSON = curry(ajax)('GET');

// 模塊B
import { getJSON } from './moduleA'; 

getJSON('/users', {name: 'John'});

延遲執(zhí)行

柯里化函數(shù)在調(diào)用時并不會立即執(zhí)行,而是返回一個函數(shù)等待完整的參數(shù)后再執(zhí)行。這讓我們可以更加靈活地控制函數(shù)的執(zhí)行時機。

let log = curry(console.log);

log('Hello'); // 不會立即執(zhí)行

setTimeout(() => {
  log('Hello'); // 2秒后執(zhí)行
}, 2000);

JavaScript中的反柯里化

概念

反柯里化(Uncurrying)與柯里化相反,它將一個接受單一參數(shù)的函數(shù)轉(zhuǎn)換成接受多個參數(shù)的函數(shù)。

// 柯里化函數(shù)  
function curriedAdd(a) {
  return function(b) {
    return a + b;
  }
}

// 反柯里化后
function uncurriedAdd(a, b) {
  return a + b; 
}

實現(xiàn)原理

反柯里化的關(guān)鍵是通過遞歸不停調(diào)用函數(shù)并傳入?yún)?shù),Until參數(shù)的數(shù)量達(dá)到函數(shù)需要的參數(shù)個數(shù)。

function uncurry(fn) {
  return function(...args) {
    let context = this;
    return args.reduce((acc, cur) => {
      return acc.call(context, cur); 
    }, fn);
  }
}

uncurry 接收一個函數(shù) fn,返回一個函數(shù)。這個函數(shù)利用reduce不停調(diào)用 fn 并傳入?yún)?shù),Until 把args所有參數(shù)都傳給 fn。

利用這個模式可以輕松實現(xiàn)反柯里化:

const curriedAdd = a => b => a + b;

const uncurriedAdd = uncurry(curriedAdd);
uncurriedAdd(1, 2); // 3

應(yīng)用場景

統(tǒng)一接口規(guī)范

有時我們會從其他模塊接收到一個柯里化的函數(shù),但我們的接口需要一個普通的多參數(shù)函數(shù)。這時可以通過反柯里化來實現(xiàn)統(tǒng)一。

// 模塊A導(dǎo)出
export const curriedGetUser = id => callback => {
  // 調(diào)用callback(user)
};

// 模塊B中
import { curriedGetUser } from './moduleA';

// 反柯里化以符合接口
const getUser = uncurry(curriedGetUser); 

getUser(123, user => {
  // use user
});

提高參數(shù)靈活性

反柯里化可以讓我們以任意順序 passes 入?yún)?shù),增加了函數(shù)的靈活性。

const uncurriedLog = uncurry(console.log);

uncurriedLog('a', 'b'); 
uncurriedLog('b', 'a'); // 參數(shù)順序靈活

支持默認(rèn)參數(shù)

柯里化函數(shù)不容易實現(xiàn)默認(rèn)參數(shù),而反柯里化后可以方便地設(shè)置默認(rèn)參數(shù)。

function uncurriedRequest(url, method='GET', payload) {
  // 請求邏輯
}

大廠面試題解析

實現(xiàn)add(1)(2)(3)輸出6的函數(shù)

這是一道典型的柯里化面試題。解析:

function curry(fn) {
  return function curried(a) {
    return function(b) {
      return fn(a, b);
    }
  }
}

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

const curriedAdd = curry(add);

curriedAdd(1)(2)(3); // 6

利用柯里化技術(shù),我們可以將普通的 add 函數(shù)轉(zhuǎn)化為 curriedAdd,它每次只接收一個參數(shù),并返回函數(shù)等待下一個參數(shù),從而實現(xiàn)了 add(1)(2)(3) 的效果。

實現(xiàn)單參數(shù)compose函數(shù)

compose函數(shù)可以將多個函數(shù)合并成一個函數(shù),這也是一道常見的柯里化面試題。解析:

function compose(fn1) {
  return function(fn2) { 
    return function(x) {
      return fn1(fn2(x));
    };
  };
}

function double(x) {
  return x * 2;
}

function square(x) {
  return x * x;
}

const func = compose(double)(square);

func(5); // 50

利用柯里化,我們創(chuàng)建了一個單參數(shù)的 compose 函數(shù),它每次返回一個函數(shù)等待下一個函數(shù)參數(shù)。這樣最終實現(xiàn)了 compose(double)(square) 的效果。

反柯里化Function.bind

Function.bind 函數(shù)實現(xiàn)了部分參數(shù)綁定,這本質(zhì)上是一個反柯里化的過程。解析:

Function.prototype.uncurriedBind = function(context) {
  const fn = this;
  return function(...args) {
    return fn.call(context, ...args);
  } 
}

function greet(greeting, name) {
  console.log(greeting, name);
}

const greetHello = greet.uncurriedBind('Hello');
greetHello('John'); // Hello John

uncurriedBind 通過遞歸調(diào)用并傳參實現(xiàn)了反柯里化,使 bind 參數(shù)從兩步變成一步傳入,這也是 Function.bind 的工作原理。

總結(jié)

柯里化和反柯里化都是非常有用的編程技巧,讓我們可以寫出更加靈活通用的函數(shù)。理解這兩種技術(shù)的實現(xiàn)原理可以幫助我們更好地運用它們。在編碼中,我們可以根據(jù)需要決定是將普通函數(shù)柯里化,還是將柯里化函數(shù)反柯里化。合理運用這兩種技術(shù)可以大大提高我們的編程效率。


網(wǎng)頁名稱:三言兩語說透柯里化和反柯里化
URL鏈接:http://m.5511xx.com/article/dpchdpp.html