摘要:中的函數(shù)式編程思想匿名函數(shù)在函數(shù)式編程語言中,函數(shù)是可以沒有名字的,匿名函數(shù)通常表示可以完成某件事的一塊代碼。匿名函數(shù)中包含對(duì)的局部變量的引用,因此當(dāng)返回時(shí),的值被保留不會(huì)被垃圾回收機(jī)制回收,持續(xù)調(diào)用,將會(huì)改變的值。
1 函數(shù)式編程簡介
函數(shù)式編程是和傳統(tǒng)命令式編程區(qū)分的一種編程思想,“在函數(shù)式編程語言中,函數(shù)是第一類的對(duì)象,也就是說,函數(shù) 不依賴于任何其他的對(duì)象而可以獨(dú)立存在,而在面向?qū)ο蟮恼Z言中,函數(shù) ( 方法 ) 是依附于對(duì)象的,屬于對(duì)象的一部分。這一點(diǎn)決定了函數(shù)在函數(shù)式語言中的一些特別的性質(zhì),比如作為傳出 / 傳入?yún)?shù),作為一個(gè)普通的變量等。[1]”
函數(shù)式編程思想的源頭可以追溯到 20 世紀(jì) 30 年代,數(shù)學(xué)家阿隆左 . 丘奇在進(jìn)行一項(xiàng)關(guān)于問題的可計(jì)算性的研究,也就是后來的 lambda 演算。lambda 演算的本質(zhì)為 一切皆函數(shù),函數(shù)可以作為另外一個(gè)函數(shù)的輸出或者 / 和輸入,一系列的函數(shù)使用最終會(huì)形成一個(gè)表達(dá)式鏈,這個(gè)表達(dá)式鏈可以最終求得一個(gè)值,而這個(gè)過程,即為計(jì)算的本質(zhì)。
然而,這種思想在當(dāng)時(shí)的硬件基礎(chǔ)上很難實(shí)現(xiàn),歷史最終選擇了同丘奇的 lambda 理論平行的另一種數(shù)學(xué)理論:圖靈機(jī)作為計(jì)算理論,而采取另一位科學(xué)家馮 . 諾依曼的計(jì)算機(jī)結(jié)構(gòu),并最終被實(shí)現(xiàn)為硬件。由于第一臺(tái)計(jì)算機(jī)即為馮 . 諾依曼的程序存儲(chǔ)結(jié)構(gòu),因此運(yùn)行在此平臺(tái)的程序也繼承了這種基因,程序設(shè)計(jì)語言如 C/Pascal 等都在一定程度上依賴于此體系。
到了 20 世紀(jì) 50 年代,一位 MIT 的教授 John McCarthy 在馮 . 諾依曼體系的機(jī)器上成功的實(shí)現(xiàn)了 lambda 理論,取名為 LISP(LISt Processor), 至此函數(shù)式編程語言便開始活躍于計(jì)算機(jī)科學(xué)領(lǐng)域。
2 JavaScript中的函數(shù)式編程思想 2.1)匿名函數(shù)在函數(shù)式編程語言中,函數(shù)是可以沒有名字的,匿名函數(shù)通常表示:“可以完成某件事的一塊代碼”。這種表達(dá)在很多場合是有用的,因?yàn)槲覀冇袝r(shí)需要用函數(shù)完成某件事,但是這個(gè)函數(shù)可能只是臨時(shí)性的,那就沒有理由專門為其生成一個(gè)頂層的函數(shù)對(duì)象。
//自定義map() function map(array, func){ var res = []; for ( var i = 0, len = array.length; i < len; i++){ res.push(func(array[i])); } return res; } //匿名函數(shù) var mapped = map([1, 3, 5, 7, 8], function (n){ return n = n + 1; }); alert(mapped); //2,4,6,8,9// 對(duì)數(shù)組 [1,3,5,7,8] 中每一個(gè)元素加 12.2)柯里化
是把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù),或者說創(chuàng)建一個(gè)已經(jīng)預(yù)先包含一個(gè)參數(shù)的函數(shù),這其中會(huì)使用到閉包。
先來一個(gè)不是類似克里化的例子:
function add(num1, num2){ return num1 + num2; } function curriedAdd(num2){ return add(5, num2); } alert(add(2, 3)); //5 alert(curriedAdd(3)); //8
這里的curriedAdd函數(shù)類似克里化,因?yàn)樗潭撕瘮?shù)的一個(gè)參數(shù)。
下面看一個(gè)真正的函數(shù)克里化:
//傳入的參數(shù)不止fn一個(gè),但是只有fn顯式用到,所以明確給出 function curry(fn){ var args = Array.prototype.slice.call(arguments, 1);//得到外部函數(shù)參數(shù) return function(){ var innerArgs = Array.prototype.slice.call(arguments);//得到內(nèi)部函數(shù)參數(shù) var finalArgs = args.concat(innerArgs);//參數(shù)合并得到整體參數(shù)數(shù)組 return fn.apply(null, finalArgs);//對(duì)整體參數(shù)數(shù)組運(yùn)用函數(shù)fn }; } function add(num1, num2){ return num1 + num2; } var curriedAdd = curry(add, 5); alert(curriedAdd(3)); //8
根據(jù)上述實(shí)例,克里化一般通過curry()函數(shù)動(dòng)態(tài)實(shí)現(xiàn),curry()函數(shù)的主要工作就是將被返回函數(shù)的參數(shù)進(jìn)行排序。 curry()的第一個(gè)參數(shù)是要進(jìn)行柯里化的函數(shù),其他參數(shù)是要傳入的值。為了獲取第一個(gè)參數(shù)之后的所有參數(shù),在 arguments 對(duì)象上調(diào)用了 slice()方法,并傳入?yún)?shù) 1 表示被返回的數(shù)組包含從第二個(gè)參數(shù)開始的所有參數(shù)。然后 args 數(shù)組包含了來自外部函數(shù)的參數(shù)。在內(nèi)部函數(shù)中,創(chuàng)建了 innerArgs 數(shù)組用來存放所有傳入的參數(shù)(又一次用到了 slice())。有了存放來自外部函數(shù)和內(nèi)部函數(shù)的參數(shù)數(shù)組后,就可以使用 concat()方法將它們組合為 finalArgs,然后使用 apply()將結(jié)果傳遞給該函數(shù)。注意這個(gè)函數(shù)并沒有考慮到執(zhí)行環(huán)境,所以調(diào)用 apply()時(shí)第一個(gè)參數(shù)是 null。
2.3)高階函數(shù)即為對(duì)函數(shù)的進(jìn)一步抽象,map(array, func) 的表達(dá)式已經(jīng)表明,將 func 函數(shù)作用于 array 中的每一個(gè)元素,最終返回一個(gè)新的 array,應(yīng)該注意的是,map 對(duì) array 和 func 的實(shí)現(xiàn)是沒有任何預(yù)先的假設(shè)的(抽象),因此稱之為“高階”函數(shù)。
function map(array, func){ var res = []; for ( var i = 0, len = array.length; i < len; i++){ res.push(func(array[i])); } return res; } var mapped = map([1, 3, 5, 7, 8], function (n){ return n = n + 1; }); alert(mapped); var mapped2 = map(["one", "two" , "three", "four"], function (item){ return "("+item+")"; }); alert(mapped2);
mapped 和 mapped2 均調(diào)用了 map,但是得到了截然不同的結(jié)果,因?yàn)?map 的參數(shù)本身已經(jīng)進(jìn)行了一次抽象,map 函數(shù)做的是第二次抽象,高階的“階”可以理解為抽象的層次。
2.4)閉包閉包已經(jīng)在另一篇文章《閉包:私有化變量》中介紹過,與閉包有關(guān)的垃圾回收機(jī)制在《垃圾回收機(jī)制——總結(jié)自《JavaScript高級(jí)程序設(shè)計(jì)》也有詳細(xì)介紹,因此這里僅僅簡要說明閉包。
當(dāng)在一個(gè)函數(shù) outter 內(nèi)部定義另一個(gè)函數(shù) inner,而 inner 又引用了 outter 作用域內(nèi)的變量,在 outter 之外使用 inner 函數(shù),則形成了閉包。
匿名函數(shù) function(){return n++;} 中包含對(duì) outter 的局部變量 n 的引用,因此當(dāng) outter 返回時(shí),n 的值被保留 ( 不會(huì)被垃圾回收機(jī)制回收 ),持續(xù)調(diào)用 o1(),將會(huì)改變 n 的值。而 o2 的值并不會(huì)隨著 o1() 被調(diào)用而改變,第一次調(diào)用 o2 會(huì)得到 n==0 的結(jié)果,用面向?qū)ο蟮男g(shù)語來說,就是 o1 和 o2 為不同的 實(shí)例,互不干涉。
閉包實(shí)例2:
//創(chuàng)建一個(gè)對(duì)象并壓入數(shù)組
var outter = [];
function clouseTest () {
var array = ["one", "two", "three", "four"];
for ( var i = 0; i < array.length;i++){
var x = {}; x.no = i; x.text = array[i]; x.invoke = function (){ alert(i); } outter.push(x); }
}
//執(zhí)行函數(shù)并調(diào)用每個(gè)數(shù)組元素對(duì)應(yīng)的對(duì)象的方法
clouseTest();// 調(diào)用這個(gè)函數(shù),向 outter 數(shù)組中添加對(duì)象
for ( var i = 0, len = outter.length; i < len; i++){
outter[i].invoke(); //4,4,4,4
}
由于 i 是閉包中的局部變量,for 循環(huán)最后退出時(shí)的值為 4,因此調(diào)用 outter 中的每個(gè)元素都會(huì)得到 4。
修正過后的閉包:
[1] http://www.ibm.com/developerw...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/80648.html
摘要:中的函數(shù)式編程思想匿名函數(shù)在函數(shù)式編程語言中,函數(shù)是可以沒有名字的,匿名函數(shù)通常表示可以完成某件事的一塊代碼。匿名函數(shù)中包含對(duì)的局部變量的引用,因此當(dāng)返回時(shí),的值被保留不會(huì)被垃圾回收機(jī)制回收,持續(xù)調(diào)用,將會(huì)改變的值。 1 函數(shù)式編程簡介 函數(shù)式編程是和傳統(tǒng)命令式編程區(qū)分的一種編程思想,在函數(shù)式編程語言中,函數(shù)是第一類的對(duì)象,也就是說,函數(shù) 不依賴于任何其他的對(duì)象而可以獨(dú)立存在,而在面向...
摘要:今天這篇文章主要介紹函數(shù)式編程的思想。函數(shù)式編程通過最小化變化使得代碼更易理解。在函數(shù)式編程里面,組合是一個(gè)非常非常非常重要的思想。可以看到函數(shù)式編程在開發(fā)中具有聲明模式。而函數(shù)式編程旨在盡可能的提高代碼的無狀態(tài)性和不變性。 最開始接觸函數(shù)式編程的時(shí)候是在小米工作的時(shí)候,那個(gè)時(shí)候看老大以前寫的代碼各種 compose,然后一些 ramda 的一些工具函數(shù),看著很吃力,然后極力吐槽函數(shù)式...
摘要:參考鏈接面向?qū)ο缶幊棠P同F(xiàn)在的很多編程語言基本都具有面向?qū)ο蟮乃枷耄热绲鹊龋嫦驅(qū)ο蟮闹饕枷雽?duì)象,類,繼承,封裝,多態(tài)比較容易理解,這里就不多多描述了。 前言 在我們的日常日發(fā)和學(xué)習(xí)生活中會(huì)常常遇到一些名詞,比如 命令式編程模型,聲明式編程模型,xxx語言是面向?qū)ο蟮牡鹊龋@個(gè)編程模型到處可見,但是始終搞不清是什么?什么語言又是什么編程模型,當(dāng)你新接觸一門語言的時(shí)候,有些問題是需...
摘要:函數(shù)式編程,一看這個(gè)詞,簡直就是學(xué)院派的典范。所以這期周刊,我們就重點(diǎn)引入的函數(shù)式編程,淺入淺出,一窺函數(shù)式編程的思想,可能讓你對(duì)編程語言的理解更加融會(huì)貫通一些。但從根本上來說,函數(shù)式編程就是關(guān)于如使用通用的可復(fù)用函數(shù)進(jìn)行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數(shù)式編程(Functional Programming),一...
閱讀 834·2021-09-22 15:18
閱讀 1184·2021-09-09 09:33
閱讀 2759·2019-08-30 10:56
閱讀 1194·2019-08-29 16:30
閱讀 1493·2019-08-29 13:02
閱讀 1463·2019-08-26 13:55
閱讀 1648·2019-08-26 13:41
閱讀 1945·2019-08-26 11:56