聽飛狐聊JavaScript設計模式系列03

本回內容介紹

上一回聊到JS的Object類型,簡單模擬了一下Java的Map,介一講,偶們來聊一下函數好唔好,介可系JS世界的一等公民喲。從函數開始,咱們就將逐步過渡到設計模式,來吧,帥狐帶你裝逼帶你飛:javascript

1. 函數的定義方式有三種

(1) 函數聲明:php

function o(a,b){
    return a+b;
}

(2) 函數表達式:css

var o = function(a,b){
    return a+b;
};

(3) 構造函數式:html

var o = new Function("a","b","return a+b");

這裏簡單的過一下函數定義,其餘函數相關的基礎知識仍是那句:請參閱書籍或其餘資料。java

2. call, apply, bind

這仨均可以改變函數內部做用域的指向,bind()是ES5的新玩意兒,IE9如下不支持。call()和apply()一起說,這倆基友僅僅是傳參不同而已,apply傳遞的是數組:node

function add(arg1,arg2) {
    return arg1+arg2;
};

function subtraction(arg1,arg2) {
    return arg1-arg2;
};
    
function optCall(arg1,arg2){
    return add.call(this,arg1,arg2);
};
    
function optApply(arg1,arg2){
    return subtraction.apply(this,[arg1,arg2]);
};
    
alert(optCall(1,2));    // 3
alert(optApply(2,1)); // 1

再來講說bind(),在高程3(JavaScript高級程序設計第三版)書上的說法是:bind()經常和回調函數與事件處理程序一塊兒使用以便在將函數做爲變量傳遞的同時保留代碼執行環境。後面的設計模式講解中咱們會有事件的講解,這裏咱們用書上的例子來模擬bind()的實現:mysql

function bind(fn,context){
    // 這裏是一個閉包
    return function(){
        // 這裏調用傳遞的函數,並將參數傳入
        return fn.apply(context,arguments);
    };
}

這裏光看例子可能有點抽象,不要緊,後面講設計模式,聊到觀察者模式的時候還會聊到事件。面試

3. 閉包與柯里化

閉包:有權訪問另外一個函數做用域中變量的函數。這是書上的解釋,有點懵吧,說白了,就是方法裏面的方法就叫閉包。
柯里化:把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數並且返回結果的新函數的技術。sql

之因此把這倆放在一塊兒來聊,是由於這倆都很差理解,有點繞,並且柯里化依賴於閉包來實現,來吧,直接看書上的例子:設計模式

var c = console;
function curry(fn){
    // 這個地方是獲取Array原型的slice方法,之因此這麼用,是由於數組未被實例化以前,沒法得到原型上的方法,可能有點繞,先無論原型後面會講
    var _slice = Array.prototype.slice;        
    // 這裏獲取的是傳入的第二個參數,也就是5
    var args = _slice.call(arguments,1);    
    c.log(args);    // [5]
    // 這裏是一個閉包,這個函數的做用是組合外部傳參和內部傳參                        
    return function(){
        // 在這裏傳入的arguments是[15,10]
        var innerArgs = _slice.call(arguments);
        c.log(innerArgs);    // [15,10]    
        var finalArgs = args.concat(innerArgs);    // 內外部數組合並
        c.log(finalArgs);    // [5,15,10]
        // 這裏寫null或是其餘均可以,由於這裏只是執行傳入的方法,也就add()方法
        return fn.apply(null,finalArgs);
    };
}

function add(a,b,c){
    return a+b+c;
}
alert(curry(add,5)(15,10));

不少盆友說這個例子木有看懂,如今配上了註釋,趕腳有木有好點。這裏沒有單獨聊閉包,由於網上關於閉包的資料已經不少了。

順便在囉嗦一句,有哥們兒面試問到了,fn.apply(null,finalArgs)這裏若是是null的話,指向的是什麼?答案是Global,而在瀏覽器環境下,Global就是window。

裝逼圖]

又是裝逼時刻了,好咯,開始敲代碼了:

這一回講的內容比較繞腦殼,其實全部的函數都是Function類型的實例。一時理解不了也不要緊,先囫圇吞棗,後面的內容還會涉及,下面仍是進入作題環節:

某客面試題,正好複習函數柯里化

聽說這家公司筆試題有四道題,這裏先聊兩道題,另外了道題後面會聊到...

1.題目:five(one(one())) 返回 511

function one(){
    var tags = typeof arguments[0];    // 獲取傳入的第一個參數類型
    var arg = "";
    switch(tags){
        // 判斷若是是undefined,說明是最裏層的函數
        case 'undefined':
            arg = 1+"";
            break;
        // 判斷若是是string,說明已經執行過最裏層函數了,也就是說,已經跑過case爲'undefined'的狀況了
        case 'string':
            arg = 1+arguments[0];
            break;
    };
    return arg;
};
function five(){
    return 5+arguments[0];
};
alert(five(one(one())));
alert(five(one(one(one(one(one(one())))))));

這個例子並不是柯里化的函數,由於每一次one()的返回都是一個字符串,可是對比函數柯里化,使函數柯里化的概念更直觀了。

咱們把這個five()改改,讓他變爲柯里化,讓帥狐show給你看:

function five(){
    var args = arguments[0];
    // 這裏就是一個閉包的體現,而後自執行,返回的依然是字符串
    return (function(){
        return 5+args;
    })();
};

怎麼樣,帥吧!好吧,若是不帥,繼續下一題,走你:

2. 題目:數組去重、並按倒數第二個字母排序

function unique(arr) {
    // res是結果數組,o是一個對象,上一回已經講過了,對象的key是不可重複的
    var res = [], o = {};
    // 遍歷傳入的數組
    for (var i=0; arr[i]!=null; i++) {
        // 這裏把數組的值做爲對象的key進行判斷,若是不存在則放入
        if (!o[arr[i]]) {
            // 這步是取過濾後的每一項放入結果數組
            res.push(arr[i]);
            // 這步把傳入值做爲對象key,而且賦值
            o[arr[i]] = true;
        }
    }
    return res;    // 返回結果數組,
}
    
alert(unique(["帥狐","帥狐",9,4,9,4,"帥","帥"]));    // 帥狐,9,4,帥

這樣就完成了數組去重,下一步,按照倒數第二個字母排序:

var arr =['javaScript','java','mongo','mysql', 'css','html','nodejs','php'];
    
function compare(pre,cur){
    var p = pre.charAt(pre.length-2);    // 取倒數第二個字母
    var c = cur.charAt(cur.length-2);
    if(p < c){ 
        return -1; 
    }else if(p > c){ 
        return 1; 
    }else{ 
        return 0; 
    }
}
    
alert(arr.sort(compare));
// 返回["mongo", "php", "nodejs", "html", "javaScript", "mysql", "css", "java"]

之因此單獨寫第二步,由於sort()排序是按照字符編碼的順序進行排序,在傳入數值的時候是有陷阱的,不會對數值大小進行排序,看例子:

var arr =[1,10,2,99,3,200];
    
function sortNum(a,b){
    return a - b
}
    
alert(arr.sort());    // 返回[1, 10, 2, 200, 3, 99]
alert(arr.sort(sortNum));    // 返回[1, 2, 3, 10, 99, 200]

這一回,主要過了一下Function類型,聊了一些函數的技巧,作了兩道題,難度適中。
下一回,咱主要聊一聊,類的模擬,原型,繼承,包括淺聊一下工廠模式,繼續裝逼繼續飛。
話說最近港囧和夏洛特煩惱惹火了不少老歌,對於喜歡聽老歌的我真的是大愛吖,dilililidilililidada...dilililidilililidada...


注:此係飛狐原創,轉載請註明出處

相關文章
相關標籤/搜索