成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

從一道面試題認(rèn)識(shí)函數(shù)柯里化

13651657101 / 1929人閱讀

摘要:函數(shù)柯里化在函數(shù)式編程中,函數(shù)是一等公民。函數(shù)柯里化的主要作用和特點(diǎn)就是參數(shù)復(fù)用提前返回和延遲執(zhí)行??赡茉趯?shí)際應(yīng)用場(chǎng)景中,很少使用函數(shù)柯里化的解決方案,但是了解認(rèn)識(shí)函數(shù)柯里化對(duì)自身的提升還是有幫助的。

最近在整理面試資源的時(shí)候,發(fā)現(xiàn)一道有意思的題目,所以就記錄下來。

題目

如何實(shí)現(xiàn) multi(2)(3)(4)=24?

首先來分析下這道題,實(shí)現(xiàn)一個(gè) multi 函數(shù)并依次傳入?yún)?shù)執(zhí)行,得到最終的結(jié)果。通過題目很容易得到的結(jié)論是,把傳入的參數(shù)相乘就能夠得到需要的結(jié)果,也就是 2X3X4 = 24。

簡單的實(shí)現(xiàn)

那么如何實(shí)現(xiàn) multi 函數(shù)去計(jì)算出結(jié)果值呢?腦海中首先浮現(xiàn)的解決方案是,閉包。

function multi(a) {
    return function(b) {
        return function(c) {
            return a * b * c;
        }
    }
}

利用閉包的原則,multi 函數(shù)執(zhí)行的時(shí)候,返回 multi 函數(shù)中的內(nèi)部函數(shù),再次執(zhí)行的時(shí)候其實(shí)執(zhí)行的是這個(gè)內(nèi)部函數(shù),這個(gè)內(nèi)部函數(shù)中接著又嵌套了一個(gè)內(nèi)部函數(shù),用于計(jì)算最終結(jié)果并返回。

單純從題面來說,似乎是已經(jīng)實(shí)現(xiàn)了想要的結(jié)果,但仔細(xì)一想就會(huì)發(fā)現(xiàn)存在問題。

上面的實(shí)現(xiàn)方案存在的缺陷:

代碼不夠優(yōu)雅,實(shí)現(xiàn)步驟需要一層一層的嵌套函數(shù)。

可擴(kuò)展性差,假如是要實(shí)現(xiàn) multi(2)(3)(4)...(n) 這樣的功能,那就得嵌套 n 層函數(shù)。

那么有沒有更好的解決方案,答案是,使用函數(shù)式編程中的函數(shù)柯里化實(shí)現(xiàn)。

函數(shù)柯里化

在函數(shù)式編程中,函數(shù)是一等公民。那么函數(shù)柯里化是怎樣的呢?

函數(shù)柯里化指的是將能夠接收多個(gè)參數(shù)的函數(shù)轉(zhuǎn)化為接收單一參數(shù)的函數(shù),并且返回接收余下參數(shù)且返回結(jié)果的新函數(shù)的技術(shù)。

函數(shù)柯里化的主要作用和特點(diǎn)就是參數(shù)復(fù)用、提前返回和延遲執(zhí)行。

例如:封裝兼容現(xiàn)代瀏覽器和 IE 瀏覽器的事件監(jiān)聽的方法,正常情況下封裝是這樣的。

var addEvent = function(el, type, fn, capture) {
    if(window.addEventListener) {
        el.addEventListener(type, function(e) {
            fn.call(el, e);
        }, capture);
    }else {
        el.attachEvent("on" + type, function(e) {
            fn.call(el, e);
        })
    }
}

該封裝的方法存在的不足是,每次寫監(jiān)聽事件的時(shí)候調(diào)用 addEvent 函數(shù),都會(huì)進(jìn)行 if else 的兼容性判斷。事實(shí)上在代碼中只需要執(zhí)行一次兼容性判斷就可以了,后續(xù)的事件監(jiān)聽就不需要再去判斷兼容性了。那么怎么用函數(shù)柯里化優(yōu)化這個(gè)封裝函數(shù)。

var addEvent = (function() {
    if(window.addEventListener) {
        return function(el, type, fn, capture) {
            el.addEventListener(type, function(e) {
                fn.call(el, e);
            }, capture);
        }
    }else {
        return function(ele, type, fn) {
            el.attachEvent("on" + type, function(e) {
                fn.call(el, e);
            })
        }
    }
})()

js 引擎在執(zhí)行該段代碼的時(shí)候就會(huì)進(jìn)行兼容性判斷,并且返回需要使用的事件監(jiān)聽封裝函數(shù)。這里使用了函數(shù)柯里化的兩個(gè)特點(diǎn):提前返回和延遲執(zhí)行。

柯里化另一個(gè)典型的應(yīng)用場(chǎng)景就是 bind 函數(shù)的實(shí)現(xiàn)。使用了函數(shù)柯里化的兩個(gè)特點(diǎn):參數(shù)復(fù)用和提前返回。

Function.prototype.bind = function(){
    var fn = this;
    var args = Array.prototye.slice.call(arguments);
    var context = args.shift();

    return function(){
        return fn.apply(context, args.concat(Array.prototype.slice.call(arguments)));
    };
};
柯里化的實(shí)現(xiàn)

那么如何通過函數(shù)柯里化實(shí)現(xiàn)面試題的功能呢?

通用版
function curry(fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function() {
        var newArgs = args.concat(Array.prototype.slice.call(arguments));
        return fn.apply(this, newArgs);
    }
}

curry 函數(shù)的第一個(gè)參數(shù)是要?jiǎng)討B(tài)創(chuàng)建柯里化的函數(shù),余下的參數(shù)存儲(chǔ)在 args 變量中。

執(zhí)行 curry 函數(shù)返回的函數(shù)接收新的參數(shù)與 args 變量存儲(chǔ)的參數(shù)合并,并把合并的參數(shù)傳入給柯里化了的函數(shù)。

function multiFn(a, b, c) {
    return a * b * c;
}
var multi = curry(multiFn);
multi(2,3,4);

結(jié)果:

雖然得到的結(jié)果是一樣的,但是很容易發(fā)現(xiàn)存在問題,就是代碼相對(duì)于之前的閉包實(shí)現(xiàn)方式較復(fù)雜,而且執(zhí)行方式也不是題目要求的那樣 multi(2)(3)(4)。那么下面就來改進(jìn)這版代碼。

改進(jìn)版

就題目而言,是需要執(zhí)行三次函數(shù)調(diào)用,那么針對(duì)柯里化后的函數(shù),如果傳入的參數(shù)沒有 3 個(gè)的話,就繼續(xù)執(zhí)行 curry 函數(shù)接收參數(shù),如果參數(shù)達(dá)到 3 個(gè),就執(zhí)行柯里化了的函數(shù)。

function curry(fn, args) {
    var length = fn.length;
    var args = args || [];
    return function(){
        newArgs = args.concat(Array.prototype.slice.call(arguments));
        if(newArgs.length < length){
            return curry.call(this,fn,newArgs);
        }else{
            return fn.apply(this,newArgs);
        }
    }
}
function multiFn(a, b, c) {
    return a * b * c;
}
var multi = curry(multiFn);
multi(2)(3)(4);
multi(2,3,4);
multi(2)(3,4);
multi(2,3)(4);

可以看到,通過改進(jìn)版的柯里化函數(shù),已經(jīng)將題目定的實(shí)現(xiàn)方式擴(kuò)展到好幾種了。這種實(shí)現(xiàn)方案的代碼擴(kuò)展性就比較強(qiáng)了,但是還是有點(diǎn)不足,就是必須事先知道求值的參數(shù)個(gè)數(shù),那能不能讓代碼更靈活點(diǎn),達(dá)到隨意傳參的效果,例如: multi(2)(3)(4),multi(5)(6)(7)(8)(9) 這樣的。

優(yōu)化版
function multi() {
    var args = Array.prototype.slice.call(arguments);
    var fn = function() {
        var newArgs = args.concat(Array.prototype.slice.call(arguments));
        return multi.apply(this, newArgs);
    }
    fn.toString = function() {
        return args.reduce(function(a, b) {
            return a * b;
        })
    }
    return fn;
}

這樣的解決方案就可以靈活的使用了。不足的是返回值是 Function 類型。

總結(jié)

就題目本身而言,是存在多種實(shí)現(xiàn)方式的,只要理解并充分利用閉包的強(qiáng)大。

可能在實(shí)際應(yīng)用場(chǎng)景中,很少使用函數(shù)柯里化的解決方案,但是了解認(rèn)識(shí)函數(shù)柯里化對(duì)自身的提升還是有幫助的。

理解閉包和函數(shù)柯里化之后,如果在面試中遇到類似的題型,應(yīng)該就可以迎刃而解了。

后記

本著學(xué)習(xí)和總結(jié)的態(tài)度寫的技術(shù)輸出,文中有任何錯(cuò)誤和問題,請(qǐng)大家指出。更多的技術(shù)輸出可以查看我的 github博客。

整理了一些前端的學(xué)習(xí)資源,希望能夠幫助到有需要的人,地址: 學(xué)習(xí)資源匯總。

參考

https://segmentfault.com/q/10...

https://blog.csdn.net/crystal...

https://mp.weixin.qq.com/s?__biz=MjM5MTA1MjAxMQ==&mid=2651228431&idx=1&sn=c9d62a30a52f4572cc0cb4aaf2a82ef3

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97071.html

相關(guān)文章

  • 一道面試談?wù)?em>函數(shù)柯里(Currying)

    摘要:忍者秘籍一書中,對(duì)于柯里化的定義如下在一個(gè)函數(shù)中首先填充幾個(gè)參數(shù)然后再返回一個(gè)新函數(shù)的技術(shù)稱為柯里化?;氐轿覀兊念}目本身,其實(shí)根據(jù)測(cè)試用例我們可以發(fā)現(xiàn),函數(shù)的要求就是接受單一函數(shù),例如但是與柯里化不同之處在于,柯里化返回的一個(gè)新函數(shù)。   歡迎大家再一次來到我的文章專欄:從面試題中我們能學(xué)到什么,各位同行小伙伴是否已經(jīng)開始了悠閑的春節(jié)假期呢?在這里提前祝大家雞年大吉吧~哈哈,之前有人說...

    cppprimer 評(píng)論0 收藏0
  • 一道柯里面試

    摘要:這是一道朋友在群里發(fā)的一道題,我之前不是很懂柯里化,就自己試著寫了一下,不知道算不算柯里化,望指教下面是題目寫好之后一下代碼可以正常運(yùn)行輸入正確我自己的代碼我用到了以下知識(shí)點(diǎn)擴(kuò)展運(yùn)算符傳參和擴(kuò)展運(yùn)算符相關(guān)的數(shù)組操作。 這是一道朋友在群里發(fā)的一道題,我之前不是很懂柯里化,就自己試著寫了一下,不知道算不算柯里化,望指教~ 下面是題目: function curry() { ...

    andycall 評(píng)論0 收藏0
  • 「前端面試系列6」理解函數(shù)柯里

    摘要:原題如下寫一個(gè)方法,當(dāng)使用下面的語法調(diào)用時(shí),能正常工作這道題要考察的,就是對(duì)函數(shù)柯里化的理解。當(dāng)參數(shù)只有一個(gè)的時(shí)候,進(jìn)行柯里化的處理。這其實(shí)就是函數(shù)柯里化的簡單應(yīng)用。 showImg(https://segmentfault.com/img/bVbopGm?w=620&h=350); 前言 這是前端面試題系列的第 6 篇,你可能錯(cuò)過了前面的篇章,可以在這里找到: ES6 中箭頭函數(shù)的...

    liaorio 評(píng)論0 收藏0
  • 關(guān)于JavaScript函數(shù)柯里探索

    摘要:函數(shù)柯里化關(guān)于函數(shù)柯里化的問題最初是在忍者秘籍中講閉包的部分中看到的,相信很多同學(xué)見過這樣一道和柯里化有關(guān)的面試題實(shí)現(xiàn)一個(gè)函數(shù),使得如下斷言能夠能夠通過簡單說就是實(shí)現(xiàn)一個(gè)求值函數(shù),能夠?qū)⑺袇?shù)相加得出結(jié)果。方法返回一個(gè)表示該對(duì)象的字符串。 函數(shù)柯里化 ??關(guān)于函數(shù)柯里化的問題最初是在《JavaScript忍者秘籍》中講閉包的部分中看到的,相信很多同學(xué)見過這樣一道和柯里化有關(guān)的面試題:...

    vboy1010 評(píng)論0 收藏0
  • 面試函數(shù)柯里

    摘要:題目發(fā)現(xiàn)一道有意思的面試題如何實(shí)現(xiàn)首先簡單分析一下,我們就能發(fā)現(xiàn)這是一個(gè)函數(shù)傳值次得到。簡單實(shí)現(xiàn)利用閉包,執(zhí)行函數(shù)時(shí)一個(gè)匿名函數(shù),用于最終返回結(jié)果。當(dāng)然,這個(gè)方法有個(gè)明顯缺陷,就是如果函數(shù)變成,我們就又要手動(dòng)嵌套一層。 題目 發(fā)現(xiàn)一道有意思的面試題:如何實(shí)現(xiàn) add(1)(2)(3)=6 ? 首先簡單分析一下,我們就能發(fā)現(xiàn)這是一個(gè)函數(shù)傳值 return3次得到6 。 簡單實(shí)現(xiàn) func...

    wudengzan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<