給你的JS類庫加上命名空間和擴展方法:jutil第一次重構


重構前的話

  上一篇發布一個JavaScript工具類庫jutil,歡迎使用,歡迎補充,歡迎挑錯!發布后有幸得到了大部分朋友的肯定,在這里多謝各位的支持鼓勵。

  在上一篇評論中,也有園友指出了存在的問題,主要有建議增加數組過濾方法,HTMLEncode和HTMLDecode方法不安全,數組去重方法的問題等,沒有命名空間,擴展不太方便。本次重構主要解決的就是上面這些問題。

  本次重構具體的就是增加了數組過濾方法,划分了一下命名空間,增加了用於擴展的方法。對於HTMLEncode和HTMLDecode方法不安全的問題,本次重構沒有處理,如果需要安全的HTMLEncode和HTMLDecode建議使用http://www.strictly-software.com/scripts/downloads/encoder.js這個JS庫。數組去重的問題我測試了一下,當數組中存在true、false等bool值時會出問題,因此改為園友(jamcode)提供的方法。

如何給類庫添加命名空間

  讓類庫擁有命名空間的方法很多,我這里用的是:

jutil.html = jutil.html ? jutil.html : {//code}

  這種方式,這里html就是二級命名空間。如之前的HTML相關的兩個方法可以寫成這樣:

(function () {
    var document = window.document;
    var jutil = jutil ? jutil : { };

    jutil.html = jutil.html ? jutil.html : {
        encode: function (sHtml) {
            var div = document.createElement("div"),
                text = document.createTextNode(sHtml);
            div.appendChild(text);
            return div.innerHTML;
        },
        decode: function (sHtml) {
            var div = document.createElement("div");
            div.innerHTML = sHtml;
            return div.innerText || div.textContent;
        }
    };

    if (!window.jutil) {
        window.jutil = jutil;
    }
})();

  本次重構就采用了這種方法。

如何讓類庫方便擴展

  這個直接參考了kit.js中的方案,就是提供了兩個用於擴展的方法:

merge : function() {
    var a = arguments;
    if(a.length < 2) {
        return;
    }
    if(a[0] != null) {
        for(var i = 1; i < a.length; i++) {
            for(var r in a[i]) {
                a[0][r] = a[i][r];
            }
        }
    }
    return a[0];
},
mergeIfNotExist : function() {
    var a = arguments;
    if(a.length < 2) {
        return;
    }
    for(var i = 1; i < a.length; i++) {
        for(var r in a[i]) {
            if(a[0][r] == null) {
                a[0][r] = a[i][r];
            }
        }
    }
    return a[0];
}

  這兩個方法都比較簡單,就不多解釋了。

重構后jutil代碼

(function () {
    var document = window.document;
    var jutil = jutil ? jutil : {
        merge : function() {
            var a = arguments;
            if(a.length < 2) {
                return;
            }
            if(a[0] != null) {
                for(var i = 1; i < a.length; i++) {
                    for(var r in a[i]) {
                        a[0][r] = a[i][r];
                    }
                }
            }
            return a[0];
        },
        mergeIfNotExist : function() {
            var a = arguments;
            if(a.length < 2) {
                return;
            }
            for(var i = 1; i < a.length; i++) {
                for(var r in a[i]) {
                    if(a[0][r] == null) {
                        a[0][r] = a[i][r];
                    }
                }
            }
            return a[0];
        }
    };

    jutil.array = jutil.array ? jutil.array : {
        distinct: function unique(arr) {
            var i = 0,
                gid = '_' + (+new Date) + Math.random(),
                objs = [],
                hash = {
                    'string': {},
                    'boolean': {},
                    'number': {}
                },
                p,
                l = arr.length,
                ret = [];
            for (; i < l; i++) {
                p = arr[i];
                if (p == null) continue;
                tp = typeof p;
                if (tp in hash) {
                    if (!(p in hash[tp])) {
                        hash[tp][p] = 1;
                        ret.push(p);
                    }
                } else {
                    if (p[gid]) continue;
                    p[gid] = 1;
                    objs.push(p);
                    ret.push(p);
                }
            }
            for (i = 0, l = objs.length; i < l; i++) {
                p = objs[i];
                p[gid] = undefined;
                delete p[gid];
            }
            return ret;
        },
        indexOf: function (arr, obj, iStart) {
            if (Array.prototype.indexOf) {
                return arr.indexOf(obj, (iStart || 0));
            }
            else {
                for (var i = (iStart || 0), j = arr.length; i < j; i++) {
                    if (arr[i] === obj) {
                        return i;
                    }
                }
                return -1;
            }
        },
        filter: function (arr, callback) {
            var result = [];
            for (var i = 0, j = arr.length; i < j; i++) {
                if (callback.call(arr[i], i, arr[i])) {
                    result.push(arr[i]);
                }
            }
            return result;
        }
    };

    jutil.html = jutil.html ? jutil.html : {
        encode: function (sHtml) {
            var div = document.createElement("div"),
                text = document.createTextNode(sHtml);
            div.appendChild(text);
            return div.innerHTML;
        },
        decode: function (sHtml) {
            var div = document.createElement("div");
            div.innerHTML = sHtml;
            return div.innerText || div.textContent;
        }
    };

    jutil.storage = jutil.storage ? jutil.storage : {
        getCookie: function (sKey) {
            if (!sKey)
                return "";
            if (document.cookie.length > 0) {
                var startIndex = document.cookie.indexOf(sKey + "=")
                if (startIndex != -1) {
                    startIndex = startIndex + sKey.length + 1
                    var endIndex = document.cookie.indexOf(";", startIndex)
                    if (endIndex == -1) {
                        endIndex = document.cookie.length;
                    }
                    return decodeURIComponent(document.cookie.substring(startIndex, endIndex));
                }
            }
            return ""
        },
        setCookie: function (sKey, sValue, iExpireSeconds) {
            if (!sKey)
                return;
            var expireDate = new Date();
            expireDate.setTime(expireDate.getTime() + iExpireSeconds * 1000);
            document.cookie = sKey + "=" + encodeURIComponent(sValue) +
            ";expires=" + expireDate.toGMTString() + ";";
        },
        deleteCookie: function (sKey) {
            if (!sKey)
                return;
            document.cookie = sKey + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
        },
        getStorage: function (sKey) {
            if (!sKey)
                return;
            if (window.localStorage) {
                return decodeURIComponent(localStorage.getItem(sKey));
            }
            else {
                return this.getCookie(sKey);
            }
        },
        setStorage: function (sKey, sValue, iExpireSeconds) {
            if (!sKey)
                return;
            if (window.localStorage) {
                localStorage.setItem(sKey, encodeURIComponent(sValue));
            }
            else {
                this.setCookie(sKey, sValue, iExpireSeconds);
            }
        },
        deleteStorage: function (sKey) {
            if (!sKey)
                return;
            if (window.localStorage) {
                localStorage.removeItem(sKey);
            }
            else {
                this.deleteCookie(sKey);
            }
        }
    };

    jutil.date = jutil.date ? jutil.date : {
        daysInFebruary: function (obj) {
            var year = 0;
            if (obj instanceof Date) {
                year = obj.getFullYear();
            }
            else if (typeof obj === "number") {
                year = obj;
            }
            else {
                return 0;
            }
            if (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {
                return 29;
            }
            return 28;
        },
        daysInYear: function (obj) {
            var year = 0;
            if (obj instanceof Date) {
                year = obj.getFullYear();
            }
            else if (typeof obj === "number") {
                year = obj;
            }
            else {
                return 0;
            }
            if (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {
                return 366;
            }
            return 365;
        },
        format: function (date, sFormat, sLanguage) {
            var time = {};
            time.Year = date.getFullYear();
            time.TYear = ("" + time.Year).substr(2);
            time.Month = date.getMonth() + 1;
            time.TMonth = time.Month < 10 ? "0" + time.Month : time.Month;
            time.Day = date.getDate();
            time.TDay = time.Day < 10 ? "0" + time.Day : time.Day;
            time.Hour = date.getHours();
            time.THour = time.Hour < 10 ? "0" + time.Hour : time.Hour;
            time.hour = time.Hour < 13 ? time.Hour : time.Hour - 12;
            time.Thour = time.hour < 10 ? "0" + time.hour : time.hour;
            time.Minute = date.getMinutes();
            time.TMinute = time.Minute < 10 ? "0" + time.Minute : time.Minute;
            time.Second = date.getSeconds();
            time.TSecond = time.Second < 10 ? "0" + time.Second : time.Second;
            time.Millisecond = date.getMilliseconds();
            time.Week = date.getDay();

            var MMMArrEn = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
                MMMArr = ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
                WeekArrEn = ["Sun", "Mon", "Tue", "Web", "Thu", "Fri", "Sat"],
                WeekArr = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
                oNumber = time.Millisecond / 1000;

            if (sFormat != undefined && sFormat.replace(/\s/g, "").length > 0) {
                if (sLanguage != undefined && sLanguage === "en") {
                    MMMArr = MMMArrEn.slice(0);
                    WeekArr = WeekArrEn.slice(0);
                }
                sFormat = sFormat.replace(/yyyy/ig, time.Year)
                .replace(/yyy/ig, time.Year)
                .replace(/yy/ig, time.TYear)
                .replace(/y/ig, time.TYear)
                .replace(/MMM/g, MMMArr[time.Month - 1])
                .replace(/MM/g, time.TMonth)
                .replace(/M/g, time.Month)
                .replace(/dd/ig, time.TDay)
                .replace(/d/ig, time.Day)
                .replace(/HH/g, time.THour)
                .replace(/H/g, time.Hour)
                .replace(/hh/g, time.Thour)
                .replace(/h/g, time.hour)
                .replace(/mm/g, time.TMinute)
                .replace(/m/g, time.Minute)
                .replace(/ss/ig, time.TSecond)
                .replace(/s/ig, time.Second)
                .replace(/fff/ig, time.Millisecond)
                .replace(/ff/ig, oNumber.toFixed(2) * 100)
                .replace(/f/ig, oNumber.toFixed(1) * 10)
                .replace(/EEE/g, WeekArr[time.Week]);
            }
            else {
                sFormat = time.Year + "-" + time.Month + "-" + time.Day + " " + time.Hour + ":" + time.Minute + ":" + time.Second;
            }
            return sFormat;
        },
        diff: function (biggerDate, smallerDate) {
            var intervalSeconds = parseInt((biggerDate - smallerDate) / 1000);
            if (intervalSeconds < 60) {
                return intervalSeconds + "秒";
            }
            else if (intervalSeconds < 60 * 60) {
                return Math.floor(intervalSeconds / 60) + "分鍾";
            }
            else if (intervalSeconds < 60 * 60 * 24) {
                return Math.floor(intervalSeconds / (60 * 60)) + "小時";
            }
            else if (intervalSeconds < 60 * 60 * 24 * 7) {
                return Math.floor(intervalSeconds / (60 * 60 * 24)) + "天";
            }
            else if (intervalSeconds < 60 * 60 * 24 * 31) {
                return Math.floor(intervalSeconds / (60 * 60 * 24 * 7)) + "周";
            }
            else if (intervalSeconds < 60 * 60 * 24 * 365) {
                return Math.floor(intervalSeconds / (60 * 60 * 24 * 30)) + "月";
            }
            else if (intervalSeconds < 60 * 60 * 24 * 365 * 1000) {
                return Math.floor(intervalSeconds / (60 * 60 * 24 * 365)) + "年";
            }
            else {
                return Math.floor(intervalSeconds / (60 * 60 * 24)) + "天";
            }
        },
        interval: function (biggerDate, smallerDate) {
            var intervalSeconds = parseInt((biggerDate - smallerDate) / 1000),
                day = Math.floor(intervalSeconds / (60 * 60 * 24)),
                hour = Math.floor((intervalSeconds - day * 24 * 60 * 60) / 3600),
                minute = Math.floor((intervalSeconds - day * 24 * 60 * 60 - hour * 3600) / 60),
                second = Math.floor(intervalSeconds - day * 24 * 60 * 60 - hour * 3600 - minute * 60);
            return day + "天:" + hour + "小時:" + minute + "分鍾:" + second + "秒";
        }
    };

    jutil.string = jutil.string ? jutil.string : {
        replaceURLWithHTMLLinks: function (sText, bBlank) {
            var pattern = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
            if (bBlank) {
                sText = sText.replace(pattern, "<a target='_blank' href='$1'>$1</a>");
            }
            else {
                sText = sText.replace(pattern, "<a href='$1'>$1</a>");
            }
            return sText;
        },
        getLength: function (sVal, bChineseDouble) {
            var chineseRegex = /[\u4e00-\u9fa5]/g;
            if (bChineseDouble != undefined && bChineseDouble === false) {
                return sVal.length;
            }
            else {
                if (chineseRegex.test(sVal)) {
                    return sVal.replace(chineseRegex, "zz").length;
                }
                return sVal.length;
            }
        }
    };

    if (!window.jutil) {
        window.jutil = jutil;
    }
})();

  其中的merge和mergeIfNotExist方法參考了園子里JS牛人薛端陽kit.js的設計。在這里也推薦一下kit.js,這是一個很優秀的JS庫。

  注意:本次重構由於加了命名空間,並且少部分方法名稱有所更改,所以上一篇博文中的示例代碼不能運行。

如何擴展

  如何用上面增加的merge方法擴展呢,這里提供一個示例。這里我們增加一個去掉數組中值為空的項:

;(function(jutil){
    jutil.array=jutil.array?jutil.array:{};
    jutil.merge(jutil.array,{
        deleteEmpty:function(arr){
            for(var i=0,j=arr.length;i<j;){
                if(arr[i]==""||arr[i]==null){
                    arr.splice(i,1);
                    j=arr.lehgth;
                }
                else{
                    i++;
                }
            }
            return arr;
        }
    });
})(jutil);

  個人感覺還是挺方便,挺簡單的。

小結

  這是我第一次真正動手寫JS類庫,真正體會到了看別人的類庫跟自己寫類庫的區別。我想園子里肯定有很多像我這樣的前端新手,想寫類庫卻不知道從哪兒下手,但願隨着這個類庫的不斷改進和重構,也能給大家一點提示和幫助。

  在此也真心希望各位有經驗的朋友多多指正,分享你們的類庫設計經驗,指出本類庫中的不足。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM