摘要:函數(shù)柯里化關(guān)于函數(shù)柯里化的問題最初是在忍者秘籍中講閉包的部分中看到的,相信很多同學(xué)見過這樣一道和柯里化有關(guān)的面試題實現(xiàn)一個函數(shù),使得如下斷言能夠能夠通過簡單說就是實現(xiàn)一個求值函數(shù),能夠?qū)⑺袇?shù)相加得出結(jié)果。方法返回一個表示該對象的字符串。
函數(shù)柯里化
??關(guān)于函數(shù)柯里化的問題最初是在《JavaScript忍者秘籍》中講閉包的部分中看到的,相信很多同學(xué)見過這樣一道和柯里化有關(guān)的面試題:
??實現(xiàn)一個add函數(shù),使得如下斷言能夠能夠通過:
add(1)(2)(3) === 6 add(1)(2,3)(4) === 10
??簡單說就是實現(xiàn)一個求值函數(shù),能夠?qū)⑺袇?shù)相加得出結(jié)果。
??分析一下:主要有兩個要點——1.拿add(1)(2)(3)來說,如果想要在add(1)后再執(zhí)行(2),那么需要add(1)返回一個函數(shù)才能做到,然后這個函數(shù)的入?yún)⑹?,依次類推。2.這種遞歸什么時候是個頭呢,貌似沒看到有什么操作能讓它停下來,這是個好問題,我們稍后解答。
??根據(jù)分析,我們先實現(xiàn)一個add函數(shù):
function add(){ let arr = []; arr = arr.concat(Array.prototype.slice.apply(arguments)) let fun = function(){ arr = arr.concat(Array.prototype.slice.apply(arguments)) return fun } return fun } console.log(add(1)(2,3)(4))
這段代碼在chrome中輸出:
? (){ arr = arr.concat(Array.prototype.slice.apply(arguments)) return fun }
??沒錯,和我們預(yù)期的一樣...因為沒法跳出遞歸調(diào)用,所以輸入了fun函數(shù),而且我們只是把參數(shù)存在了數(shù)組arr中,但是沒有做累加計算。繼續(xù)改進(jìn)函數(shù):
function add(){ let arr = []; arr = arr.concat(Array.prototype.slice.apply(arguments)) let fun = function(){ arr = arr.concat(Array.prototype.slice.apply(arguments)) return fun } fun.getValue = function(){ return arr.reduce(function(total, num){ return total+num }, 0) } return fun } console.log(add(1,2)(2,3)(4).getValue()) //12
??現(xiàn)在可以輸出正確的值了,我們給fun函數(shù)添加了一個函數(shù)getValue,用于將記錄參數(shù)的數(shù)組中的元素求和。但是這樣需要在add函數(shù)后調(diào)用一下getValue,這好像與需求有點差異...
valueOf()和toString()??這時候,我們想到兩個方法valueOf()和toString(),這兩個都是定義在Object原型上的方法,他們有什么特別嗎?
Object.prototype.valueOf()
用 MDN 的話來說,valueOf() 方法返回指定對象的原始值。
??JavaScript 調(diào)用 valueOf() 方法用來把對象轉(zhuǎn)換成原始類型的值(數(shù)值、字符串和布爾值)。但是我們很少需要自己調(diào)用此函數(shù),valueOf 方法一般都會被 JavaScript 自動調(diào)用。
??記住上面這句話,下面我們會細(xì)說所謂的自動調(diào)用是什么意思。
Object.prototype.toString()
toString() 方法返回一個表示該對象的字符串。
??每個對象都有一個 toString() 方法,當(dāng)對象被表示為文本值時或者當(dāng)以期望字符串的方式引用對象時,該方法被自動調(diào)用。
??這里先記住,valueOf() 和 toString() 在特定的場合下會自行調(diào)用。
??????????????????——摘自ChokCoco《一道面試題引發(fā)的對javascript類型轉(zhuǎn)換的思考》
??簡單來說就是,這兩個函數(shù)會在特定的場合下被js引擎隱式調(diào)用,當(dāng)然兩個函數(shù)被調(diào)用的條件是不同的,這里不展開分析,可參考《一道面試題引發(fā)的對javascript類型轉(zhuǎn)換的思考》。
??我們繼續(xù)改造add函數(shù):
function add(){ let arr = []; arr = arr.concat(Array.prototype.slice.apply(arguments)) let fun = function(){ arr = arr.concat(Array.prototype.slice.apply(arguments)) return fun } fun.toString = function(){ console.log(222) return arr.reduce(function(total, num){ return total+num }, 0) } return fun } console.log(add(1,2)(2,3)(4))
??先不執(zhí)行它,我們來分析一下。我們重寫了fun函數(shù)的toString方法,假設(shè)它會被js引擎調(diào)用,我們調(diào)用了reduce方法來為數(shù)組中的元素求和然后return出來,看起來沒什么毛病對吧?
??首先在chrome(62.0.3202.94)上執(zhí)行一下這段代碼,看到了什么?
? 12 222 222
??是不是很詭異?我想要的是12,這f 12是什么鬼...222輸出了兩遍又是什么東東,更詭異的是,先輸出了f 12后輸出了222...
??chrome上輸出f 12,我們可以寫一個更簡潔的函數(shù)來模擬:
var app = function(){}; app.toString = function(){ console.log("toString") return 12 }; function app1(){ return app }; console.log(app1())
??輸出結(jié)果和上面完全一樣,但至于為什么先輸出f 12以及為什么輸出兩遍222,這個需要剖析chrome底層機(jī)制了,此處不做討論。(暫時還沒搞明白,后續(xù)搞清楚了會更新上來,如果有大神清楚可以在下面評論。)
??再來看FireFox(57.0)中的表現(xiàn):
??無語了吧,直接無視咱寫的toString方法,該啥樣還啥樣...
??再來看看IE(11):
??啥也不說了,再瞅瞅node:
??一臉懵逼啊...雖然不知道為什么不同環(huán)境會輸出這些,但可以肯定的一點是——toString方法都沒有被正常執(zhí)行。所以,為了規(guī)避這個問題,我們需要讓js引擎更明確地知道我們想調(diào)用toString,所以,修改一下打印語句:
console.log(""+add(1,2)(2,3)(4))
現(xiàn)在再看看,是不是所有環(huán)境輸出都正常了:
222 12
??如果你是用valueOf,也會有類似的問題,只需將打印語句改為:
console.log(+add(1,2)(2,3)(4))console.log()和alert()
??除了上述的解決方法之外,還可以使用alert函數(shù)來輸出結(jié)果,即:
alert(add(1,2)(2,3)(4))
??大家可自行測試,除node外,瀏覽器中都可以彈出“12”。這是為啥呢?alert和console.log不一樣嗎?
??還真不一樣,console.log可輸入任何類型的數(shù)據(jù),然而alert只能輸出String類型的數(shù)據(jù),所以...懂了吧?
??最后建議大家平時自己寫代碼不要像本例這樣,在toString/valueOf函數(shù)中做數(shù)值運(yùn)算,而且慎用類型轉(zhuǎn)換。本文作為填坑記錄,有不對的地方歡迎指正,文中的問題有大神有見解可以在評論區(qū)討論。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/90066.html
摘要:上傳進(jìn)度下面通過高階函數(shù)的方式我們來實現(xiàn)函數(shù)節(jié)流節(jié)流函數(shù)計時器是否是第一次調(diào)用首次調(diào)用直接放行存在計時器就攔截設(shè)置使用節(jié)流分時函數(shù)節(jié)流函數(shù)為我們提供了一種限制函數(shù)被頻繁調(diào)用的解決方案。 高階函數(shù)是指至少滿足下列條件之一的函數(shù) 1:函數(shù)可以作為參數(shù)被傳遞 2:函數(shù)可以作為返回值輸出 JavaScript語言中的函數(shù)顯然的是滿足了高階函數(shù)的條件,下面我們一起來探尋JavaScript種高階...
摘要:本書主要探索函數(shù)式編程的核心思想。我們在中應(yīng)用的僅僅是一套基本的函數(shù)式編程概念的子集。我稱之為輕量級函數(shù)式編程。通常來說,關(guān)于函數(shù)式編程的書籍都熱衷于拓展閱讀者的知識面,并企圖覆蓋更多的知識點。,本書統(tǒng)稱為函數(shù)式編程者。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 譯者團(tuán)隊(排名不分先后)...
摘要:為了盡可能提升互通性,已經(jīng)成為函數(shù)式編程庫遵循的實際標(biāo)準(zhǔn)。與輕量級函數(shù)式編程的概念相反,它以火力全開的姿態(tài)進(jìn)軍的函數(shù)式編程世界。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關(guān)于譯者:這是一個流淌著滬江血液的純粹工程:認(rèn)真,是 HTML 最堅實的梁柱;分享,是 CSS 里最閃耀的一瞥;總結(jié),...
摘要:高階函數(shù)函數(shù)式編程中,接受函數(shù)作為參數(shù),或者返回一個函數(shù)作為結(jié)果的函數(shù)通常就被稱為高階函數(shù)。均屬于高階函數(shù),高階函數(shù)并不神秘,我們?nèi)粘>幊桃矔玫健⒖佳菟愫瘮?shù)式編程指南入門康托爾哥德爾圖靈永恒的金色對角線原文函數(shù)與演算 緣起 造了一個輪子,根據(jù)GitHub項目地址,生成項目目錄樹,直觀的展現(xiàn)項目結(jié)構(gòu),以便于介紹項目。歡迎Star。 repository-tree 技術(shù)棧: ES6 ...
摘要:原文鏈接和都支持函數(shù)的柯里化函數(shù)的柯里化還與的函數(shù)編程有很大的聯(lián)系如果你感興趣的話可以在這些方面多下功夫了解相信收獲一定很多看本篇文章需要知道的一些知識點函數(shù)部分的閉包高階函數(shù)不完全函數(shù)文章后面有對這些知識的簡單解釋大家可以看看什么是柯里化 原文鏈接 Haskell和scala都支持函數(shù)的柯里化,JavaScript函數(shù)的柯里化還與JavaScript的函數(shù)編程有很大的聯(lián)系,如果你感興...
閱讀 2469·2021-09-27 13:36
閱讀 2167·2019-08-29 18:47
閱讀 2133·2019-08-29 15:21
閱讀 1399·2019-08-29 11:14
閱讀 1984·2019-08-28 18:29
閱讀 1629·2019-08-28 18:04
閱讀 573·2019-08-26 13:58
閱讀 3210·2019-08-26 12:12