1. 程式人生 > >javascript函數語言程式設計之curry化

javascript函數語言程式設計之curry化

        函數語言程式設計是一種程式設計正規化(程式設計思想,不要以為有啥模板),主要思想是將運算過程儘量寫成一系列巢狀的函式。舉個例子

//宣告式
let d = a + b + c * d;

//函式式
let d = add(a,add(b,mul(c,d)))

例子沒有啥難度吧,那麼函數語言程式設計的函式和數學的函式有什麼關係呢,其實函數語言程式設計的函式就是數學裡的函式

                                                             y = f(x)

對應的每一個相同的x總會得到相同的y,即純函式的定義。

函式式還有一些特性

      函式是"第一等公民": 函式可以是變數,在JavaScript中就不用解釋了

      沒有"副作用": 即不改變函式外部狀態,跟純函式差不多,想想怎樣的函式才會對相同的x有不同的y呢,當然是引用了外部變數唄,比如

let t = 1;
function f (){//不是純函式,而且還有副作用
    let x = t;
    t--;
    return x;
}

     不修改狀態:給沒有副作用差不多意思,不改變外部狀態

     引用透明性: 純函式的定義,對於任意的相同輸入,都有相同的輸出

概念扯完了,來本文重點內容,函數語言程式設計的curry

curry(柯里化):是把接受多個引數的函式變換成接受一個單一引數(最初函式的第一個引數)的函式,並且返回接受餘下的引數而且返回結果的新函式的技術。

如果不理解就來看個例子

function add4(a,b,c,d){
   return a + b + c + d;
}
add4(1,2,3,4)//未柯里化

//那麼柯里化的應該能這麼用
add4_curry(1)(2)(3)(4)//柯里化

現在我們來實現一個curry化函式

我們想要的curry化函式是這樣的

let add4 = curry(function(a,b,c,d) {//使用curry化函式
   return a + b + c + d;
});

add4(1)(2,3)(4);

先看es5版的

/**
 *
 * @param fn
 * @returns {function(): function()}
 */
function curry(fn) {
  var args = [], // 裝總的引數的陣列
      n = fn.length; //傳入的函式的引數個數
  return function core() { //返回一個接任意個引數的函式
    var arg = [].slice.call(arguments); //獲取當前函式的引數
    args = args.concat(arg);
    n -= arg.length;
    return n === 0 ? fn.apply(null, args) : core;
  }
}

//使用如下
var add4 = curry(function (a, b, c, d) {
  return a + b + c + d;
});
console.log(add4(1, 2)(2)(3));

認真看,應該能看懂

然後再來個es6版的


const curry = (fn, n = fn.length, args = []) => n === 0 ? fn(...args) : (...args1) => curry(fn, n - args1.length, [...args, ...args1]);

//舉例
const add5 = curry((a, b, c, d, e) => a + b + c + d + e);

console.log(add5(1, 2)(3, 4)(5));

感謝es6提供的箭頭函式和...運算子以及函式預設引數,才能把curry函式一行就寫完,其實原理和es5版差不多。

現在來說說函數語言程式設計的curry化到底有什麼用,第一個用途,引數記憶,即對於多引數的函式我可以記憶前面的引數

比如

//add4的例子
let add1 = add4(1,2,3)
add1(4)//輸出10
add1(5)//輸出11
add1(6)//輸出12

可以看到,我把add4的引數1,2,3給記憶下來了,然後如果其他地方得用到引數1,2,3的話就沒必要寫了,這部分的其他應用就留給讀者去實踐了。

第二Function.prototype.bind的實現,學過react的人絕對熟悉這個東西,而Funtion.prototype.bind的實現也利用了curry化的原理,不妨來實現個bind函式

Function.prototype.bind = function () {
  var args = [].slice.call(arguments);//第一部分引數
  var that = args.shift();//第一個引數為待繫結的this
  var fn = this;//當前呼叫bind的函式
  return function () {//curry化
    var args1 = [].slice.call(arguments);//第二部分引數
    return fn.apply(that, args.concat(args1));
  }
};

//使用一下
function test(a,b) {
  console.log(this,a,b);
}
var t = test.bind({a:1,b:2},1);
t(2);

不過往原型上加東西通常是不好的,所有還是寫個bind 函式吧

function bind(fn) {
  var args = [].slice.call(arguments);
  args.shift();//除去fn
  var that = args.shift();//this引數
  return function () {
    var args1 = [].slice.call(arguments);//第二部分引數
    return fn.apply(that, args.concat(args1));
  }
}

var getById = bind(document.getElementById, document);
getById("name");

函數語言程式設計在react,redux等一些前端框架中使用非常廣泛,建議讀者可以好好學習一下這方面知識。

關於函數語言程式設計還有偏函式,函式組合,管道,函子等很多內容,後面我的部落格會慢慢補上。

相關推薦

javascript語言程式設計curry

        函數語言程式設計是一種程式設計正規化(程式設計思想,不要以為有啥模板),主要思想是將運算過程儘量寫成一系列巢狀的函式。舉個例子 //宣告式 let d = a + b + c * d; //函式式 let d = add(a,add(b,mul(c,d))

語言程式設計 Python

  1 函數語言程式設計概述      前提:函式在 Python 中是⼀等物件      工具:built-in ⾼階函式;lambda 函式;operator 模組;functools 模組      模式:閉包與裝飾器      替代:⽤用 List Comprehension 可輕鬆替代 m

關於JavaScript語言程式設計的思考

前幾天看到掘金上有兩篇關於JavaScript函數語言程式設計的爭論,有人建議不用for迴圈,有的人又說太過函式式不好。我自己也是一個喜歡函數語言程式設計的人,所以寫了這篇文章想和大家分享一些我個人喜歡的建議,最後也有一些我自己的思考。 第一次在掘金髮文章,各位同行手下留情,有錯誤歡迎指出。 1、給函式清

語言程式設計陣列的語言程式設計

5. 陣列的函數語言程式設計 在本章中,我們將建立一組用於陣列的函式,並用函式式的方法而非命令式的方法來解決常見的問題 5.1 陣列的函式式方法 本節將建立一組有用的函式,並用它們解決陣列的常見問題 本節所建立的所有函式稱為投影函式,把函式應用

語言程式設計組合與管道

7. 組合與管道 昨天我們學習了柯里化與偏函式,當然不能學完就完了,一些經典的函式什麼的還是需要記一下的,比如今天重寫新寫一下看看能不能寫出來,也能加深自己對這方面的理解。 今天我們將要學習的是函式式組合的含義及其實際應用。 Q 函式式組合在函數語言程式設計中被

語言程式設計-bind函式

Bind函式 Bind函式在函數語言程式設計中是如此重要,以至於函數語言程式設計語言會為bind函式設計語法糖。另一個角度Bind函式非常難以理解,幾乎很少有人能通過簡單的描述說明白bind函式的由來及原理。 這篇文章試圖通過“人話”來描述bind函式,並通過淺顯的例項為零函數語言程式設計語言的開發者揭祕bi

java8語言程式設計Consumer

Consumer< T>介面接受一個T型別引數,沒有返回值。 public interface Consumer<T> { void accept(T t);

深入學習javascript語言程式設計

大家都知道JavaScript可以作為面向物件或者函式式程式語言來使用,一般情況下大家理解的函數語言程式設計無非包括副作用、函式組合、柯里化這些概念,其實並不然,如果往深瞭解學習會發現函數語言程式設計還包括非常多的高階特性,比如functor、monad等。國外課程網站egghead上有個教授(名字叫Fris

學會JavaScript語言程式設計(第1部分)

摘要: JS函數語言程式設計入門。 原文:學會使用函數語言程式設計的程式設計師(第1部分) 作者:前端小智 Fundebug經授權轉載,版權歸原作者所有。 在這篇由多部分組成的文章中,接下來將介紹函數語言程式設計的一些概念,這些概念對你學習函數語言程式設計有所幫助。如果你已經懂了什麼是

C#語言程式設計可選值

      在我們的實際開發中已經會遇到可空型別,而在C#中自從2.0之後就提供了可空型別(Nullable<T>),普通的值型別是不可以賦值為NULL,但是在型別的後面加上問號就變成了可空型別,這樣就可以賦值為NULL了。當然這樣的方式也可以用於函數語言程式設計中,但函數語言程式設計有自己的獨特

學會JavaScript語言程式設計(第3部分)

摘要: JS函數語言程式設計入門。 原文:學會使用函數語言程式設計的程式設計師(第3部分) 作者:前端小智 Fundebug經授權轉載,版權歸原作者所有。 本系列的其它篇: 學會使用函數語言程式設計的程式設計師(第1部分) 學會使用函數語言程式設計的程式設計師

Python學習筆記 -- 語言程式設計高階函式

函數語言程式設計 函數語言程式設計(Functional Programming),是一種抽象程度很高的程式設計正規化,純粹的函數語言程式設計語言編寫的函式沒有變數。因此,任意一個函式,只要輸入是確定的,輸出就是確定的。 函數語言程式設計是一種"程式設計正規化"(pro

java語言程式設計Supplier

描述:Supplier< T>介面沒有入參,返回一個T型別的物件,類似工廠方法。 原始碼: public interface Supplier<T> { /** * Gets a result. *

語言程式設計根-拉姆達運算/演算(λ-calculus)

1930s初,普林斯頓大學的邏輯學家阿倫佐·丘奇 (Alonzo Church,1903-1995) 開發出了一種新的形式系統(formal system),即拉姆達運算/演算 (λ-calculus

Python進階學習筆記——語言程式設計返回函式&閉包

1、返回函式 Python中除了返回函式值之外,還可以返回函式,就像前面說的,函式也可以看做一個變數,那麼返回函式的意義在於什麼呢?——延緩函式的呼叫,有什麼應用場景暫且還不知道,後續理解補充。總之,可以想呼叫該返回的函式的時候再呼叫。 用慕課網上廖老師的例子說明一下:

Java8語言程式設計物件轉換

一.簡單介紹 通常當我們呼叫介面得到資料時需要轉換一個物件成我們內部程式碼中定義的資料結構, 使用java8的Function和Stream‘s map可以很方便高效的完成轉換。 在我們開始之前,有兩個概念要了解。 第一個是一個接受一個引數併產生結果的java.uti

語言程式設計memories

純函式:是這樣一種函式,即相同的輸入,永遠會得到相同的輸出,而且沒有任何可觀察的副作用。這樣的純函式好處便是可以進行快取,稱之為memorize,只是下面的函式不夠健壯function memorize(fn) {    let cache = {}   return fun

JavaScript 語言程式設計到底是個啥

隨著大前端時代的到來,在產品開發過程中,前端所佔業務比重越來越大、互動越來越重。傳統的老夫拿起JQuery就是一把梭應付當下重互動頁面已經十分乏力。於是乎有了Angular,React,Vue這些現代框架。 但隨之而來的還有大量的新知識新名詞,如MVC,MVVM,Flu

語言程式設計函式返回值&裝飾器

一、函式返回值 1.什麼是函式返回值 顧名思義,函式返回值,就是一個函式的返回值,是一個函式名的情況 2.閉包 以計算多個數之和為例: 方法一:直接呼叫函式 def cacl_sum(*args): all_sum = 0 for i

JavaScript語言程式設計

1:基本概念 函數語言程式設計是一種程式設計思維方式,並不是一些語法規則,對於複用性高的功能程式碼進行一定的函式封裝,實現了程式碼