深入理解Javascript函數(shù)編程

閱讀作者原文
初階部分
字符串可以保存為變量,函數(shù)說(shuō)他也可以

var autumn = 'autumnswind';
        var autumn_fn = function() {
            return 'autumnswind';
        };

字符串可以保存對(duì)象字段耐朴,函數(shù)說(shuō)他也可以

var autumnswind = {
            autumn: 'autumnswind',
            autumn_fn: function() {
                return 'autumnswind'
            }
        };

字符串可以用時(shí)再創(chuàng)建手销,函數(shù)說(shuō)他也可以

'Autumns' + (function() {
            return 'Wind'
        })();

字符串可以作為參數(shù)傳給函數(shù),函數(shù)說(shuō)他也可以

var autumn;
        function autumn_fn(){};
        function hellloWorld(autumn, autumn_fn) {
            return;
        }

字符串可以作為函數(shù)返回值碧信,函數(shù)說(shuō)他也可以

return 'autumnswind';
        return function() {
            return 'autumnswind';
        };

所以函數(shù)真的是JS里面的上等好公民啊可以穿梭于任何地方,并談笑風(fēng)生
高階部分:
有了上面的例子输涕,那么我們就可以把函數(shù)這個(gè)小孩子帶到好多好玩的地方,往下慢慢看~
首先看第一個(gè)例子

var
            obj1 = {
                value: '秋風(fēng)'
            },
            obj2 = {
                value: 'autumnswind'
            },
            obj3 = {
                value: '莎娜'
            };
        var values = [];

        function add(obj) {
            values.push(obj.value);
        }
        add(obj1);
        add(obj2);
        console.log(values); // 秋風(fēng),autumnswind

這種寫法慨畸,大家都知道了莱坎,變量會(huì)污染全局環(huán)境,并且一旦有一個(gè)地方忘記修改了就會(huì)變得很不穩(wěn)定寸士,不像函數(shù)體一樣檐什,只負(fù)責(zé)內(nèi)部的輸入輸出碴卧,這里如果融入上下文的其他函數(shù)和變量就會(huì)變得非常混亂

根據(jù)這樣修改成第二個(gè)例子:

var
            obj1 = {
                value: '秋風(fēng)'
            },
            obj2 = {
                value: 'autumnswind'
            },
            obj3 = {
                value: '莎娜'
            };

        function add(obj) {
            var values = [];
            values.push(obj.value);
            return values;
        }
        跟下面一樣
        /*function add(obj) {
            var values = [];
            var accumulate = function() {
                values.push(obj.value);
            };
            accumulate();
            return values;
        }*/
        add(obj1);
        add(obj2);
        console.log(add(obj1)); // 秋風(fēng)
        console.log(add(obj2)); // autumnswind

這樣我們把values數(shù)組聲明放進(jìn)去函數(shù)內(nèi)部乃正,這樣就不會(huì)被其他外部變量騷擾了住册,但是問(wèn)題又來(lái)了,只有最后傳入對(duì)象值才可以返回瓮具,那不是我們的初衷

最后看消除所有尷尬的第三個(gè)例子:

var
            obj1 = {
                value: '秋風(fēng)'
            },
            obj2 = {
                value: 'autumnswind'
            },
            obj3 = {
                value: '莎娜'
            };
        var
            Add = function(obj) {
                var
                    values = [];
                var
                    _calc = function(obj) {
                        if (obj) {
                            values.push(obj.value);
                            return values;
                        } else {
                            return values;
                        }
                    };
                return _calc;
                //可以這樣把它看成匿名函數(shù)省去一個(gè)沒(méi)必要的變量
                /*return function(obj) {
                    if (obj) {
                        values.push(obj.value);
                        return values;
                    } else {
                        return values;
                    }
                }*/
            };
        var
            calc = Add();
        calc(obj1); //相當(dāng)于ValueAccumulator()(obj1)
        calc(obj2); //走if分支
        console.log(calc()); //走else的分支

這里制造一個(gè)閉包來(lái)保存第一層函數(shù)的values數(shù)組荧飞,這個(gè)數(shù)組既可以被內(nèi)部函數(shù)_calc調(diào)用,也可以在自己函數(shù)體內(nèi)調(diào)用名党;第一層函數(shù)的關(guān)鍵點(diǎn)在于返回的是在自己內(nèi)部定義的那個(gè)函數(shù)_calc叹阔,這個(gè)hack就能讓Add函數(shù)在外部能訪問(wèn)函數(shù)體內(nèi)的一直保存的values數(shù)組,進(jìn)一步說(shuō)這種方法可以得到第一層函數(shù)任何一個(gè)聲明的變量传睹,這是閉包的一個(gè)很常見(jiàn)的用法(返回函數(shù))耳幢。

理解下面這些話

JS中的閉包就是函數(shù)可以訪問(wèn)父作用域(這個(gè)總結(jié)夠短的,有爭(zhēng)議的可以先擱置爭(zhēng)議)

上面其實(shí)可以看做是自執(zhí)行的匿名函數(shù)(_calc可以它看成一個(gè)匿名函數(shù)輸出來(lái))欧啤,自執(zhí)行的函數(shù)實(shí)際上是高階函數(shù)的一種形式睛藻。高階函數(shù)就是以其它函數(shù)為輸入,或者返回一個(gè)函數(shù)為輸出的函數(shù)(這個(gè)理解越來(lái)越像是閉包的理解了)

所以函數(shù)將其他函數(shù)作為輸入?yún)?shù)或者作為返回值邢隧,就可以稱為高階函數(shù)

上面其實(shí)還需要了解一個(gè)知識(shí)點(diǎn)就是純函數(shù)

//非純函數(shù)
        var autumn1 = function(str) {
            window.innerHeight;
            window.innerWidth;
            return str + 's innerHeight: ' + window.innerWidth + 'px';
        };
        //純函數(shù)
        var autumn2 = function(str, height) {
            return str + 's innerHeight: ' + height + 'px';
        };
        console.log(autumn1('autumnswind'));
        console.log(autumn2('autumnswind', 254));

兩個(gè)函數(shù)的區(qū)別在于非純函數(shù)依賴window這個(gè)全局對(duì)象的狀態(tài)來(lái)計(jì)算寬度和高度店印,而自給自足的純函數(shù)則要求這些值作為參數(shù)傳入,當(dāng)一個(gè)函數(shù)是純的府框,也就是不依賴于當(dāng)前狀態(tài)和環(huán)境吱窝,我們就不用管它實(shí)際的計(jì)算結(jié)果是什么時(shí)候被計(jì)算出來(lái)。

純函數(shù)返回的計(jì)算結(jié)果僅與傳入的參數(shù)相關(guān)

純函數(shù)是完完全全獨(dú)立的迫靖,所以它適合被重復(fù)調(diào)用使用院峡,為下面的函數(shù)編程做一個(gè)好鋪墊

有更深刻理解或者有誤的話請(qǐng)務(wù)必提醒并留言我~

回到題目核心的JS函數(shù)編程
由于JS中,函數(shù)是頭等公民系宜,這里的實(shí)際意思就是函數(shù)被認(rèn)定最基本最根本的類型照激,正如數(shù)字和對(duì)象一樣。 如果數(shù)字和對(duì)象可以被來(lái)回傳遞盹牧,那么函數(shù)(函數(shù)我為什么就不可以呢)也可以的俩垃。
這就是JS函數(shù)編程的基本思想吧

那下面第四段代碼就是在第三段代碼后面的基礎(chǔ)上再添加,實(shí)現(xiàn)這種思路

var calc2 = Add();
        var objects = [obj1, obj2, obj3]; // 這個(gè)數(shù)組可以很大
        objects.forEach(calc2);
//注意對(duì)象foeEach的用法 array.forEach(callbackfn[, thisArg])汰寓;對(duì)于數(shù)組中的每個(gè)元素口柳,forEach都會(huì)調(diào)用callbackfn函數(shù)一次
        console.log(calc2());

這里的calc2函數(shù)就變成一個(gè)‘變量’進(jìn)入到forEach參數(shù)內(nèi)

我們可以在這個(gè)基礎(chǔ)上繼續(xù)擴(kuò)充功能,第五段代碼有滑,鏈?zhǔn)秸{(diào)用

objects1 = objects.reverse();
        objects2 = objects1.concat([4, 16]);
        objects3 = objects2.map(Math.sqrt);
        console.log(objects3);

用jQuery用多了跃闹,就會(huì)知道,jq習(xí)慣把類似上面的代碼鏈?zhǔn)秸{(diào)用
類似這樣把代碼串在一起

console.log(['秋風(fēng)', 'autumnswind', '莎娜'].reverse().concat([4, 16]).map(Math.sqrt)); //NaN,NaN,NaN,2,4
//寫明顯一點(diǎn)
/*console.log(
            ['秋風(fēng)', 'autumnswind', '莎娜']
            .reverse()
            .concat([4, 16])
            .map(Math.sqrt)
            );*/

這樣用的前提必須是這個(gè)函數(shù)對(duì)象里面擁有這個(gè)方法,換句話說(shuō)就是Array.prototype有這個(gè)方法(例如reverse, concat ,map)
給他擴(kuò)充一個(gè)簡(jiǎn)單的方法如下:

Array.prototype.make4 = function() {
            console.log(this[4]);
            //this.length=4;
            return this[4];
        }
        console.log(['秋風(fēng)', 'autumnswind', '莎娜'].reverse().concat([4, 16]).map(Math.sqrt).make4()); //4

上面除了展示匿名函數(shù)望艺,鏈?zhǔn)秸{(diào)用苛秕,還有有一種方法是函數(shù)式編程里面常用的,就是遞歸

var Add2 = function(n) {
            if (n < 0) {
                // 基準(zhǔn)情形
                return 'I am autumnswind';
            } else {
                // 遞歸情形
                return Add2(n - 1);
            }
        }
        console.log(Add2(5));

注意找默,基準(zhǔn)情形就是讓遞歸停止下來(lái)的條件艇劫,防止無(wú)限遞歸

再?gòu)?fù)雜點(diǎn)就叫分而治之,其實(shí)數(shù)學(xué)界很多問(wèn)題都可以用遞歸解決的

var Add3 = function(a, b) {
            if (a < 0 && b == 8) {
                console.log(a % b); //-1
                // 基準(zhǔn)情形
                return 'I am autumnswind';
            } else {
                // 遞歸情形
                return Add3(a - 1, b);
            }
        }
        console.log(Add3(5, 8));
        console.log(Add3(5, 7)); //Maximum call stack size exceeded
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惩激,一起剝皮案震驚了整個(gè)濱河市店煞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌咧欣,老刑警劉巖浅缸,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異魄咕,居然都是意外死亡衩椒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門哮兰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)毛萌,“玉大人,你說(shuō)我怎么就攤上這事喝滞「蠼” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵右遭,是天一觀的道長(zhǎng)做盅。 經(jīng)常有香客問(wèn)我,道長(zhǎng)窘哈,這世上最難降的妖魔是什么吹榴? 我笑而不...
    開(kāi)封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮滚婉,結(jié)果婚禮上图筹,老公的妹妹穿的比我還像新娘。我一直安慰自己让腹,他們只是感情好远剩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著骇窍,像睡著了一般瓜晤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腹纳,一...
    開(kāi)封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天痢掠,我揣著相機(jī)與錄音哈恰,去河邊找鬼。 笑死志群,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蛔钙。 我是一名探鬼主播锌云,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吁脱!你這毒婦竟也來(lái)了桑涎?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤兼贡,失蹤者是張志新(化名)和其女友劉穎攻冷,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遍希,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡等曼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凿蒜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片禁谦。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖废封,靈堂內(nèi)的尸體忽然破棺而出州泊,到底是詐尸還是另有隱情,我是刑警寧澤漂洋,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布遥皂,位于F島的核電站,受9級(jí)特大地震影響刽漂,放射性物質(zhì)發(fā)生泄漏演训。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一爽冕、第九天 我趴在偏房一處隱蔽的房頂上張望仇祭。 院中可真熱鬧,春花似錦颈畸、人聲如沸乌奇。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)礁苗。三九已至,卻和暖如春徙缴,著一層夾襖步出監(jiān)牢的瞬間试伙,已是汗流浹背嘁信。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疏叨,地道東北人潘靖。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蚤蔓,于是被迫代替她去往敵國(guó)和親卦溢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容