成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

三言兩語說透柯里化和反柯里化

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

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

JavaScript中的柯里化

概念

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

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

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

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

實現原理

實現柯里化的關鍵是通過閉包保存函數參數。以下是柯里化函數的一般模式:

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函數接受一個fn函數為參數,返回一個curried函數。curried函數檢查接收的參數個數args.length是否滿足fn函數需要的參數個數fn.length。如果滿足,則直接調用fn函數;如果不滿足,則繼續返回curried函數等待接收剩余參數。

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

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

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

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

應用場景

參數復用

柯里化可以讓我們輕松復用參數。例如:

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

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

提前返回函數副本

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

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

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

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

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

延遲執行

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

let log = curry(console.log);

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

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

JavaScript中的反柯里化

概念

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

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

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

實現原理

反柯里化的關鍵是通過遞歸不停調用函數并傳入參數,Until參數的數量達到函數需要的參數個數。

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

uncurry 接收一個函數 fn,返回一個函數。這個函數利用reduce不停調用 fn 并傳入參數,Until 把args所有參數都傳給 fn。

利用這個模式可以輕松實現反柯里化:

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

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

應用場景

統一接口規范

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

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

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

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

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

提高參數靈活性

反柯里化可以讓我們以任意順序 passes 入參數,增加了函數的靈活性。

const uncurriedLog = uncurry(console.log);

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

支持默認參數

柯里化函數不容易實現默認參數,而反柯里化后可以方便地設置默認參數。

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

大廠面試題解析

實現add(1)(2)(3)輸出6的函數

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

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

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

實現單參數compose函數

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

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

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

反柯里化Function.bind

Function.bind 函數實現了部分參數綁定,這本質上是一個反柯里化的過程。解析:

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 通過遞歸調用并傳參實現了反柯里化,使 bind 參數從兩步變成一步傳入,這也是 Function.bind 的工作原理。

總結

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

責任編輯:姜華 來源: 宇宙一碼平川
相關推薦

2023-07-30 15:14:19

Koa蔥圈模型

2023-08-07 08:01:09

Vuewebpack開發

2017-12-11 15:02:46

Javascript函數式編程currying

2023-08-04 07:26:55

工廠類集中化設計模式

2023-08-03 08:01:27

單例模式結構開發

2023-08-07 06:30:15

抽象工廠模式軟件設計模式

2023-08-08 20:13:36

設計模式原型模式

2023-08-15 11:07:37

適配器模式TypeScript

2023-08-05 13:31:20

工廠方法模式對象

2023-07-27 15:04:10

Node.js核心API

2020-12-03 08:23:23

函數柯里化代碼

2020-09-23 16:07:52

JavaScript函數柯里化

2021-09-28 07:12:10

avaScriptCurrying柯里化

2025-01-27 00:30:29

柯里化JavaScript函數

2016-09-22 15:50:38

JavascriptRedux源碼解析

2023-06-28 08:34:02

Bind()函數JavaScript

2009-08-04 17:49:31

Web Page生命周ASP.NET Pos

2023-10-21 12:52:26

2024-07-15 14:49:38

2009-08-05 11:14:33

ASP.NET ISA
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美自拍网站 | 国产精品黄 | 国产成人99久久亚洲综合精品 | 凹凸日日摸日日碰夜夜 | 91国在线| h视频免费在线观看 | 国产一区二区三区在线看 | 国产成人自拍一区 | 精品一区二区久久 | 欧美国产激情 | 狠狠久久久 | 欧美激情久久久 | 日韩国产一区二区三区 | 欧美爱爱视频网站 | 午夜三区| 男人av在线| 久久av一区二区 | 久久69精品久久久久久久电影好 | 国产欧美日韩一区 | 精品在线一区二区三区 | 美女国内精品自产拍在线播放 | 一区二区播放 | 特黄毛片| 人人干人人干人人干 | 日韩在线中文字幕 | 亚洲欧美在线观看视频 | 国产九九精品视频 | 亚洲国产精品一区二区www | 久久精品国产v日韩v亚洲 | 精品一二三区 | 国户精品久久久久久久久久久不卡 | 亚洲国产精品一区二区久久 | 亚州综合在线 | 久久成人亚洲 | 久久久精品一区二区 | 国产成人精品免费 | 午夜欧美| 日本欧美在线观看视频 | 亚洲看片网站 | 涩涩导航 | 伊人网站在线 |