• 给你的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类库,真正体会到了看别人的类库跟自己写类库的区别。我想园子里肯定有很多像我这样的前端新手,想写类库却不知道从哪儿下手,但愿随着这个类库的不断改进和重构,也能给大家一点提示和帮助。

      在此也真心希望各位有经验的朋友多多指正,分享你们的类库设计经验,指出本类库中的不足。

  • 相关阅读:
    iOS进阶二-KVC
    iOS进阶一OC对象的本质
    2019-01-19
    2019-01-12
    2019
    2018-12-23 随笔
    2018-12-18 随笔
    2018-12-10
    2018-12-01
    2018.11.23 随笔
  • 原文地址:https://www.cnblogs.com/artwl/p/2585165.html
Copyright © 2020-2023  润新知