js比较器组件Comparator.js

比较器

在平常的业务中,值比较不仅仅是“==”或“===”,而是具有业务意义的值比较,比如查询条件的比较,数组值比较和业务日期的值比较等等。在编译语言中,例如java,可以重写hashcode和equal方法来进行引用类型比较,而基本类型比较则通过“==”来进行比较,那么js中是否可以这么做?当然可以,前提是在Object.prototype中添加hashcode和equal方法,但这种方式存在对象属性引入,容易造成未知属性污染。所以比较器组件Comparator.js,在进行组件式开发中,就尤其有用。


Comparator.js

    var class2type = {}, toString = class2type.toString, 
        map2type = {
            "string": ["boolean", "number", "date", "regexp"],
            "number": ["string", "boolean"],
            "array": "object",
            "date": "string",
            "regexp": "string"
        };

        //遍历数组元素进行处理.
        function each(args, cb) {
            var i = 0, len = args.length;
            for(; i < len; i++) {
                cb(i, args[i]);
            }
        }

        //两个类型比较.
        function _compare(src, target) {
            if(src === target) return true; 
            var srcType = class2type[toString.call(src)], targetType = class2type[toString.call(target)];
            //类型相同时
            if(srcType === targetType) {
                if(srcType === "string" || srcType === "number" || srcType === "boolean") {
                    return src === target;
                } else if(srcType === "object") {
                    return this.compareObject(src, target);
                } else if(srcType === "array") {
                    return this.compareArray(src, target);
                } else if(srcType === "date") {
                    return this.compareDate(src, target);
                } else if(srcType === "regexp") {
                    return this.compareRegExp(src, target);
                }
            //类型可以比较时   
            } else if(this.canComparable(srcType, targetType)) {
                if(srcType === "string") {
                    if(targetType === "boolean") {
                        return this.compareBoolean(src, target);
                    } else if(targetType === "number") {
                        return src === String(target);  
                    } else if(targetType === "date") {
                        return this.compareDate(src, target);   
                    } else if(targetType === "regexp") {
                        return this.compareRegExp(src, target); 
                    }
                } else if(srcType === "number") {
                    return this.compareNumber(Number(src), Number(target));
                } else if(srcType === "array") {
                    return this.compareArray(src, target);
                } else if(srcType === "date") {
                    return this.compareDate(src, target);
                } else if(srcType === "regexp") {
                    return this.compareRegExp(src, target);
                }
            }
            return false;
        }

        //时间比较, 只能比较到日.
        function _compareDate(dSrc, dTarget) {
            var srcType = class2type[toString.call(dSrc)], 
                targetType = class2type[toString.call(dTarget)];
            if(srcType === targetType) {
                return _dateFormat(dSrc, "yyyy-MM-dd") === _dateFormat(dTarget, "yyyy-MM-dd");  
            } else if(srcType === "date") {
                return _dateFormat(dSrc, "yyyy-MM-dd") === dTarget; 
            } else if(srcType === "string") {
                return dSrc === _dateFormat(dTarget, "yyyy-MM-dd"); 
            }       
        }

        //格式化日期显示.
       function _dateFormat(date, fmtStr) {
            if(!fmtStr || typeof fmtStr != "string") return date;
            var fmt = { //按字母分开
                "M+": date.getMonth() + 1, //月
                "d+": date.getDate(), //日
                "h+": date.getHours(), //时
                "m+": date.getMinutes(), //分
                "s+": date.getSeconds(), //秒
                "q+": Math.floor(date.getMonth() + 3) / 3, //季度
                "S": date.getMilliseconds() //毫秒 
            };
            date = typeof date === "string" && new Date(+String(date.match(/\d+/))) || 
                typeof date === "number" && new Date(date) || new Date();
            fmtStr = /(y+)/.test(fmtStr) && fmtStr.replace(RegExp.$1, 
                (date.getFullYear() + "").substr(4 - RegExp.$1.length)) || fmtStr;
            for(var k in fmt) {
                if(new RegExp("(" + k + ")").test(fmtStr)) {
                    fmtStr = fmtStr.replace(RegExp.$1, RegExp.$1.length == 1 ? fmt[k] : 
                        ("00" + fmt[k]).substr(("" + fmt[k]).length));
                }
            }
            return fmtStr;
        }

        //正则表达式比较.
        function _compareRegExp(eSrc, eTarget) {
            var srcType = class2type[toString.call(eSrc)], 
                targetType = class2type[toString.call(eTarget)];
            if(srcType === targetType) {
                return eSrc.source === eTarget.source;
            } else if(srcType === "string") {
                return eSrc === eTarget.source;
            } else if(srcType === "regexp") {
                return eSrc.source === eTarget;
            }       
        }

        //布尔类型值比较.
        function _compareBoolean(iSrc, iTarget) {
            var srcType = class2type[toString.call(iSrc)], 
                targetType = class2type[toString.call(iTarget)];
            if(srcType === "string") {
                iSrc = iSrc.replace(/\s+/g, "");
            }
            if(iTarget === "string") {
                iTarget = iTarget.replace(/\s+/g, "");
            }
            return Boolean(iSrc) === Boolean(iTarget);
        }

        //两个数组进行比较.
        function _compareArray(srcArr, targetArr) {
            if(srcArr.length != targetArr.length) {
                return false;
            }
            if(srcArr.sort) {
                srcArr.sort();
            }
            if(targetArr.sort) {
                targetArr.sort();
            }
            for(var i = 0, len = srcArr.length; i < len; i++) {
                if(srcArr[i] != targetArr[i] && !this.compare(srcObj[name], targetObj[name])) {
                    return false;
                }
            }
            return true;
        }

        //两个对象进行值比较.
        function _compareObject(srcObj, targetObj) {
            var srcProps = [], targetProps = [], name = null;
            for(name in srcObj) srcProps.push(name);
            for(name in targetObj) targetProps.push(name);
            if(srcProps.length != targetProps.length) {
                return false;
            }
            for(name in srcObj) {
                if(srcObj[name] != targetObj[name] && !this.compare(srcObj[name], targetObj[name])) {
                    return false;
                }
            }
            return true;
        }

        //两个类型是否可以比较.
        function _canComparable(sType, tType) {
            return map2type[sType].indexOf(tType) > -1;
        }

        //两个数字进行比较, 这里设置精度为8位.
        function _compareNumber(srcNum, targetNum) {
            return Number(srcNum).toFixed(8) === Number(targetNum).toFixed(8);
        }

        //类型添加.
        each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
            class2type[ "[object " + name + "]" ] = name.toLowerCase();
        });

        //定义比较器.
        var Comparator = {
            compare: _compare,
            compareArray: _compareArray,
            compareBoolean: _compareBoolean,
            compareDate: _compareDate,
            compareRegExp: _compareRegExp,
            compareObject: _compareObject,
            compareNumber: _compareNumber, 
            canComparable: _canComparable,
            getInstance: function() {
                var comparator = {};
                for(var name in this) {
                    if(name !== "getInstance" && this[name]) {
                        comparator[name] = this[name];
                    }
                }
                return comparator;
            }
        };
        //return Comparator;

测试

<html>
    <script type="text/javascript" src="./Comparator.js">script>
    <script>
        var obj1 = {name: "a", age: 17}, obj2 = {name: "a", age: 18};
        //alert(Comparator.compare(obj1, obj2));

        var obj3 = {name: "1", age: 2, person: obj1}, obj4 = {name: "1", age: 2, person: obj2};
        alert(Comparator.compare(obj3, obj4));

        var date1 = "2017-09-24", date2 = new Date();
        //alert(Comparator.compare(date1, date2));

        var arr1 = [1,2,3,4,5], arr2 = [1,3,4,2,5];
        //alert(Comparator.compare(arr1, arr2));
    script>
html>

结论

对js中的基本类型进行值比较,而不是简单的“==”和“===”在业务应用中十分常见,js相对与java来说,缺少hashcode和equal方法,那么以js组件进行api的抽取,来达到通用的值比较则具有一定的实践意义。

你可能感兴趣的:(js)