中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久

深入解析JavaScript中函數的Currying柯里化
來源:易賢網 閱讀:1135 次 日期:2016-07-19 14:44:55
溫馨提示:易賢網小編為您整理了“深入解析JavaScript中函數的Currying柯里化”,方便廣大網友查閱!

這篇文章主要介紹了JavaScript中函數的Currying柯里化,Currying 的重要意義在于可以把函數完全變成"接受一個參數、返回一個值"的固定形式,需要的朋友可以參考下

引子

先來看一道小問題:

有人在群里出了到一道題目:

var s = sum(1)(2)(3) ....... 最后 alert(s) 出來是6  

var s = sum(1)(2)(3)(4) ....... 最后 alert(s) 出來是10  

問sum怎么實現?

剛看到題目,我第一反應是sum返回的是一個function,但是沒有最終實現,印象中看到過類似的原理,但是記不清了。

后來同事說,這個是叫柯里化,

實現方法比較巧妙:

function sum(x){ 

 var y = function(x){ 

  return sum(x+y) 

 } 

 y.toString = y.valueOf = function(){ 

  return x; 

 } 

 return y; 

下面我們就深入來看一下currying柯里化~

什么是柯里化?

柯里化是這樣的一個轉換過程,把接受多個參數的函數變換成接受一個單一參數(注:最初函數的第一個參數)的函數,如果其他的參數是必要的,返回接受余下的參數且返回結果的新函數。

當我們這么說的時候,我想柯里化聽起來相當簡單。JavaScript中是怎么實現的呢?

假設我們要寫一個函數,接受3個參數。

var sendMsg = function (from, to, msg) {

 alert(["Hello " + to + ",", msg, "Sincerely,", "- " + from].join("\n"));

};

現在,假定我們有柯里化函數,能夠把傳統的JavaScript函數轉換成柯里化后的函數:

var sendMsgCurried = curry(sendMsg); 

// returns function(a,b,c)

var sendMsgFromJohnToBob = sendMsgCurried("John")("Bob"); 

// returns function(c)

sendMsgFromJohnToBob("Come join the curry party!"); 

//=> "Hello Bob, Come join the curry party! Sincerely, - John"

手動柯里化

在上面的例子中,我們假定擁有神秘的curry函數。我會實現這樣的函數,但是現在,我們首先看看為什么這樣的函數是如此必要。

舉個例子,手動柯里化一個函數并不困難,但是確實有點啰嗦:

// uncurried

var example1 = function (a, b, c) {

// do something with a, b, and c

};

// curried

var example2 = function(a) {

 return function (b) {

  return function (c) {

// do something with a, b, and c

  };

 };

};

在JavaScript,即使你不指定一個函數所有的參數,函數仍將被調用。這是個非常實用JavaScript的功能,但是卻給柯里化制造了麻煩。

思路是每一個函數都是有且只有一個參數的函數。如果你想擁有多個參數,你必須定義一系列相互嵌套的函數。討厭!這樣做一次兩次還可以,可是需要以這種方式定義需要很多參數的函數的時候,就會變得相當啰嗦和難于閱讀。(但是別擔心,我會馬上告訴你一個辦法)

一些函數編程語言,像Haskell和OCaml,語法中內置了函數柯里化。在這些語言中,舉個例子,每個函數是擁有一個參數的函數,并且只有一個參數。你可能會認為這種限制麻煩勝過好處,但是語言的語法就是這樣,這種限制幾乎無法察覺。

舉個例子,在OCaml,你可以用兩種方式定義上面example:

let example1 = fun a b c ->

// (* do something with a, b, c *)

let example2 = fun a ->

 fun b ->

  fun c ->

// (* do something with a, b, c *)

很容易看出這兩個例子和上面的那兩個例子是如何的相似。

區別,然而,是否在OCaml也是做了同樣的事情。OCaml,沒有擁有多個參數的函數。但是,在一行中聲明多個參數就是嵌套定義單參函數“快捷方式”。

類似的 ,我們期待調用柯里化函數句法上和OCaml中調用多參函數類似。我們期望這樣調用上面的函數:

example1 foo bar baz

example2 foo bar baz

而在JavaScript,我們采用明顯不同的方式:

example1(foo, bar, baz);

example2(foo)(bar)(baz);

在OCaml這類語言中,柯里化是內置的。在JavaScript,柯里化雖然可行(高階函數),但是語法上是不方便的。這也是為什么我們決定編寫一個柯里化函數來幫我們做這些繁瑣的事情,并使得我們的代碼簡潔。

創建一個curry輔助函數

理論上我們期望可以有一個方便的方式轉換普通老式的JavaScript函數(多個參數)到完全柯里化的函數。

這個想法不是我獨有的,其他的人已經實現過了,例如在wu.js 庫中的.autoCurry()函數(盡管你關心的是我們自己的實現方式)。

首先,讓我們創建一個簡單的輔助函數 .sub_curry:

function sub_curry(fn 

/*, variable number of args */

) {

 var args = [].slice.call(arguments, 1);

 return function () {

  return fn.apply(this, args.concat(toArray(arguments)));

 };

}

讓我們花點時間看看這個函數的功能。相當簡單。sub_curry接受一個函數fn作為它的第一個參數,后面跟著任何數目的輸入參數。返回的是一個函數,這個函數返回fn.apply執行結果,參數序列合并了該函數最初傳入參數的,加上fn調用的時候傳入參數的。

看例子:

var fn = function(a, b, c) { return [a, b, c]; };

// these are all equivalent

fn("a", "b", "c");

sub_curry(fn, "a")("b", "c");

sub_curry(fn, "a", "b")("c");

sub_curry(fn, "a", "b", "c")();

//=> ["a", "b", "c"]

很明顯,這并不是我門想要的,但是看起來有點柯里化的意思了。現在我們將定義柯里化函數curry:

function curry(fn, length) {

// capture fn's # of parameters

 length = length || fn.length;

 return function () {

  if (arguments.length < length) {

// not all arguments have been specified. Curry once more.

   var combined = [fn].concat(toArray(arguments));

   return length - arguments.length > 0 

    ? curry(sub_curry.apply(this, combined), length - arguments.length)

    : sub_curry.call(this, combined );

  } else {

// all arguments have been specified, actually call function

   return fn.apply(this, arguments);

  }

 };

}

這個函數接受兩個參數,一個函數和要“柯里化”的參數數目。第二個參數是可選的,如果省略,默認使用Function.prototype.length 屬性,就是為了告訴你這個函數定義了幾個參數。

最終,我們能夠論證下面的行為:

var fn = curry(function(a, b, c) { return [a, b, c]; });

// these are all equivalent

fn("a", "b", "c");

fn("a", "b", "c");

fn("a", "b")("c");

fn("a")("b", "c");

fn("a")("b")("c");

//=> ["a", "b", "c"]

我知道你在想什么…

等等…什么?!

難道你瘋了?應該是這樣!我們現在能夠在JavaScript中編寫柯里化函數,表現就如同OCaml或者Haskell中的那些函數。甚至,如果我想要一次傳遞多個參數,我可以向我從前做的那樣,用逗號分隔下參數就可以了。不需要參數間那些丑陋的括號,即使是它是柯里化后的。

這個相當有用,我會立即馬上談論這個,可是首先我要讓這個Curry函數前進一小步。

柯里化和“洞”(“holes”)

盡管柯里化函數已經很牛了,但是它也讓你必須花費點小心思在你所定義函數的參數順序上。終究,柯里化的背后思路就是創建函數,更具體的功能,分離其他更多的通用功能,通過分步應用它們。

當然這個只能工作在當最左參數就是你想要分步應用的參數!

為了解決這個,在一些函數式編程語言中,會定義一個特殊的“占位變量”。通常會指定下劃線來干這事,如過作為一個函數的參數被傳入,就表明這個是可以“跳過的”。是尚待指定的。

這是非常有用的,當你想要分步應用(partially apply)一個特定函數,但是你想要分布應用(partially apply)的參數并不是最左參數。

舉個例子,我們有這樣的一個函數:

var sendAjax = function (url, data, options) { 

/* ... */

 }

也許我們想要定義一個新的函數,我們部分提供SendAjax函數特定的Options,但是允許url和data可以被指定。

當然了,我們能夠相當簡單的這樣定義函數:

var sendPost = function (url, data) {

 return sendAjax(url, data, { type: "POST", contentType: "application/json" });

};

或者,使用使用約定的下劃線方式,就像下面這樣:

var sendPost = sendAjax( _ , _ , { type: "POST", contentType: "application/json" });

注意兩個參數以下劃線的方式傳入。顯然,JavaScript并不具備這樣的原生支持,于是我們怎樣才能這樣做呢?

回過頭讓我們把curry函數變得智能一點…

首先我們把我們的“占位符”定義成一個全局變量。

var _ = {};

我們把它定義成對象字面量{},便于我們可以通過===操作符來判等。

不管你喜不喜歡,為了簡單一點我們就使用_來做“占位符”。現在我們就可以定義新的curry函數,就像下面這樣:

function curry (fn, length, args, holes) {

 length = length || fn.length;

 args = args || [];

 holes = holes || [];

 return function(){

  var _args = args.slice(0),

   _holes = holes.slice(0),

   argStart = _args.length,

   holeStart = _holes.length,

   arg, i;

  for(i = 0; i < arguments.length; i++) {

   arg = arguments[i];

   if(arg === _ && holeStart) {

    holeStart--;

    _holes.push(_holes.shift()); 

// move hole from beginning to end

   } else if (arg === _) {

    _holes.push(argStart + i); 

// the position of the hole.

   } else if (holeStart) {

    holeStart--;

    _args.splice(_holes.shift(), 0, arg); 

// insert arg at index of hole

   } else {

    _args.push(arg);

   }

  }

  if(_args.length < length) {

   return curry.call(this, fn, length, _args, _holes);

  } else {

   return fn.apply(this, _args);

  }

 }

}

實際代碼還是有著巨大不同的。 我們這里做了一些關于這些“洞”(holes)參數是什么的記錄。概括而言,運行的職責是相同的。

展示下我們的新幫手,下面的語句都是等價的:

var f = curry(function(a, b, c) { return [a, b, c]; });

var g = curry(function(a, b, c, d, e) { return [a, b, c, d, e]; });

// all of these are equivalent

f("a","b","c");

f("a")("b")("c");

f("a", "b", "c");

f("a", _, "c")("b");

f( _, "b")("a", "c");

//=> ["a", "b", "c"]

// all of these are equivalent

g(1, 2, 3, 4, 5);

g(_, 2, 3, 4, 5)(1);

g(1, _, 3)(_, 4)(2)(5);

//=> [1, 2, 3, 4, 5]

瘋狂吧?!

我為什么要關心?柯里化能夠怎么幫助我?

你可能會停在這兒思考…

這看起來挺酷而且…但是這真的能幫助我編寫更好的代碼?

這里有很多原因關于為什么函數柯里化是有用的。

函數柯里化允許和鼓勵你分隔復雜功能變成更小更容易分析的部分。這些小的邏輯單元顯然是更容易理解和測試的,然后你的應用就會變成干凈而整潔的組合,由一些小單元組成的組合。

為了給一個簡單的例子,讓我們分別使用Vanilla.js, Underscore.js, and “函數化方式” (極端利用函數化特性)來編寫CSV解析器。

Vanilla.js (Imperative)

//+ String -> [String]

var processLine = function (line){

 var row, columns, j;

 columns = line.split(",");

 row = [];

 for(j = 0; j < columns.length; j++) {

  row.push(columns[j].trim());

 }

};

//+ String -> [[String]]

var parseCSV = function (csv){

 var table, lines, i; 

 lines = csv.split("\n");

 table = [];

 for(i = 0; i < lines.length; i++) {

  table.push(processLine(lines[i]));

 }

 return table;

};

Underscore.js

//+ String -> [String]

var processLine = function (row) {

 return _.map(row.split(","), function (c) {

  return c.trim();

 });

};

//+ String -> [[String]]

var parseCSV = function (csv){

 return _.map(csv.split("\n"), processLine);

};

函數化方式

//+ String -> [String]

var processLine = compose( map(trim) , split(",") );

//+ String -> [[String]]

var parseCSV = compose( map(processLine) , split("\n") );

所有這些例子功能上是等價的。我有意的盡可能的簡單的編寫這些。

想要達到某種效果是很難的,但是主觀上這些例子,我真的認為最后一個例子,函數式方式的,體現了函數式編程背后的威力。

關于curry性能的備注

一些極度關注性能的人可以看看這里,我的意思是,關注下所有這些額外的事情?

通常,是這樣,使用柯里化會有一些開銷。取決于你正在做的是什么,可能會或不會,以明顯的方式影響你。也就是說,我敢說幾乎大多數情況,你的代碼的擁有性能瓶頸首先來自其他原因,而不是這個。

有關性能,這里有一些事情必須牢記于心:

1.存取arguments對象通常要比存取命名參數要慢一點

2.一些老版本的瀏覽器在arguments.length的實現上是相當慢的

3.使用fn.apply( … ) 和 fn.call( … )通常比直接調用fn( … ) 稍微慢點

4.創建大量嵌套作用域和閉包函數會帶來花銷,無論是在內存還是速度上

5.在大多是web應用中,“瓶頸”會發生在操控DOM上。這是非常不可能的,你在所有方面關注性能。顯然,用不用上面的代碼自行考慮。

更多信息請查看網絡編程
由于各方面情況的不斷調整與變化,易賢網提供的所有考試信息和咨詢回復僅供參考,敬請考生以權威部門公布的正式信息和咨詢為準!
關于我們 | 聯系我們 | 人才招聘 | 網站聲明 | 網站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點

版權所有:易賢網

中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久
日韩免费高清av| 国产综合久久久久影院| 亚洲码国产岛国毛片在线| 免费人成网站在线观看欧美高清| 国产成人精品综合在线观看| 欧美精品高清视频| 亚洲影视在线播放| 欧美伊人久久大香线蕉综合69| 久久免费国产精品| 国产米奇在线777精品观看| 日韩免费视频一区| 青娱乐精品在线视频| 欧美一区二区三区四区五区| 亚洲五月六月丁香激情| 成人丝袜18视频在线观看| 久久久www免费人成精品| 国产精品一线二线三线精华| 久久亚洲一区二区三区明星换脸| 六月丁香婷婷色狠狠久久| 精品国产一区二区三区久久影院| 奇米色一区二区| 欧美成人三级电影在线| 国产综合色在线视频区| 国产精品久久看| 色综合久久天天| 一区二区三区色| 欧美三级日本三级少妇99| 亚洲国产成人av网| 欧美一区二区三区婷婷月色| 黄页视频在线91| 亚洲国产精品成人综合| 99精品视频一区二区三区| 一区二区三区四区不卡在线| 欧美日韩精品专区| 久久99蜜桃精品| 国产精品美女久久久久久久| 在线日韩一区二区| 麻豆免费精品视频| 欧美激情一区二区三区不卡| 97成人超碰视| 蜜桃视频在线观看一区| 久久精品人人做| 在线视频综合导航| 极品尤物av久久免费看| 中文字幕一区在线观看视频| 欧美日韩免费观看一区二区三区| 蜜桃av噜噜一区| 国产精品久久久久一区二区三区| 欧美自拍丝袜亚洲| 国产美女久久久久| 亚洲成人自拍偷拍| 中文乱码免费一区二区| 欧美日韩亚洲综合在线 | 欧美a一区二区| 欧美妇女性影城| 高清在线观看日韩| 免费欧美在线视频| 亚洲色大成网站www久久九九| 69堂亚洲精品首页| 91首页免费视频| 国产在线精品视频| 日韩成人精品在线| 亚洲激情六月丁香| 久久久99久久精品欧美| 欧美日韩国产区一| 99久久免费视频.com| 精品一区二区三区在线播放| 中文字幕一区二区三| 国产无一区二区| 欧美精品一区二区久久婷婷 | 国产精品美女一区二区三区| 日韩欧美亚洲另类制服综合在线| 色噜噜狠狠成人中文综合| 国产传媒欧美日韩成人| 激情综合网av| 久久99精品一区二区三区| 日韩制服丝袜先锋影音| 亚洲电影在线免费观看| 亚洲国产日韩综合久久精品| 亚洲精品欧美在线| 亚洲欧美在线另类| 国产精品成人在线观看| 国产精品入口麻豆九色| 久久久久久**毛片大全| 精品国产乱码久久久久久老虎| 91精品福利在线一区二区三区| 欧美视频在线一区二区三区| 91久久精品网| 欧美日韩一区二区三区在线看| 91国内精品野花午夜精品| 在线中文字幕一区| 欧美精品日韩精品| 日韩免费视频一区二区| 精品国产91乱码一区二区三区| 精品国产sm最大网站| 久久久国产综合精品女国产盗摄| 久久毛片高清国产| 国产精品久久久久影视| 夜夜亚洲天天久久| 日本aⅴ免费视频一区二区三区 | 亚洲区小说区图片区qvod| 成人欧美一区二区三区在线播放| 亚洲欧洲av在线| 丝瓜av网站精品一区二区| 久久精品国产久精国产| 国产精品99精品久久免费| 久久www免费人成看片高清| 精品在线观看免费| 国产精品小仙女| 国产激情视频一区二区三区欧美| 国产91精品免费| 色婷婷av一区二区| 91成人网在线| 日韩欧美亚洲国产另类| 中文字幕精品一区二区三区精品| 国产精品嫩草久久久久| 视频在线在亚洲| 国产成人av电影| 91黄色小视频| xfplay精品久久| 亚洲视频在线观看一区| 美女在线观看视频一区二区| 成人黄色电影在线| 91精品视频网| 国产精品久久久久久久浪潮网站| 亚洲国产成人porn| jlzzjlzz亚洲日本少妇| 91精品国产综合久久蜜臀| 国产精品久久久久四虎| 韩国精品一区二区| 欧美丝袜丝nylons| 欧美经典三级视频一区二区三区| 午夜电影久久久| 99国产精品久久久久| 精品国产麻豆免费人成网站| 亚洲福利国产精品| 91网站在线观看视频| 久久综合九色综合久久久精品综合| 一区二区三区.www| 99麻豆久久久国产精品免费 | 久久国产精品免费| 在线看国产一区二区| 日本一区二区视频在线| 另类小说一区二区三区| 欧美日韩激情一区二区三区| 国产精品毛片无遮挡高清| 久久99久久99精品免视看婷婷 | 国产精品动漫网站| 国产成人精品aa毛片| 51午夜精品国产| 亚洲国产综合色| 欧美日韩一区二区三区四区五区| 久久精品视频在线免费观看| 国产又黄又大久久| 欧美亚洲综合在线| 亚洲国产中文字幕| 在线视频你懂得一区| 夜夜精品视频一区二区| 色一情一伦一子一伦一区| 精品国产乱码久久久久久浪潮 | 成人黄色小视频| 国产精品色眯眯| 99久久婷婷国产精品综合| 亚洲视频一区二区在线| jlzzjlzz欧美大全| 亚洲美女少妇撒尿| 91国产免费观看| 亚洲成av人片一区二区三区| 欧美日韩在线综合| 日韩电影在线看| 精品国产欧美一区二区| 国产iv一区二区三区| 国产精品久久久久久久久搜平片| 99精品视频在线免费观看| 亚洲与欧洲av电影| 欧美一级日韩不卡播放免费| 激情欧美一区二区| 欧美一区二区在线观看| 国产在线精品免费av| 亚洲美女电影在线| 日韩欧美在线影院| 成人av资源站| 午夜精品123| 久久久午夜精品| 色香蕉成人二区免费| 免费成人在线视频观看| 欧美国产一区在线| 欧美日韩一区二区三区免费看| 久久精品国产久精国产| 中文字幕亚洲一区二区av在线| 麻豆国产91在线播放| 综合av第一页| 国产精品亲子乱子伦xxxx裸| 亚洲精品一区二区三区在线观看| 欧美精品一级二级| 欧美日韩激情一区二区| 精品视频免费看| 欧美日韩午夜影院| 欧美日韩国产成人在线91| 在线精品视频一区二区三四|