/*        
        关于JS相等比较算法(==)的原理
        
        比较运算x==y, 其中x和 y是值,产生true或者false。这样的比较按如下方式进行:
        1.若Type(x)与Type(y)相同, 则
        a.若Type(x)为Undefined, 返回true。
        b.若Type(x)为Null, 返回true。
        c.若Type(x)为Number, 则
        i.  若x为NaN, 返回false。 
        ii. 若y为NaN, 返回false。 
        iii.若x与y为相等数值, 返回true。 
        iv. 若x 为 +0 且 y为−0, 返回true。 
        v.  若x 为 −0 且 y为+0, 返回true。 
        vi. 返回false。//出自http://www.cnblogs.com/ahjesus 尊重作者辛苦劳动成果,转载请注明出处,谢谢!
        d.若Type(x)为String, 则当x和y为完全相同的字符序列(长度相等且相同字符在相同位置)时返回true。 否则, 返回false。 
        e.若Type(x)为Boolean, 当x和y为同为true或者同为false时返回true。 否则, 返回false。 
        f.当x和y为引用同一对象时返回true。否则,返回false。
        2.若x为null且y为undefined, 返回true。 
        3.若x为undefined且y为null, 返回true。 //出自http://www.cnblogs.com/ahjesus 尊重作者辛苦劳动成果,转载请注明出处,谢谢!
        4.若Type(x) 为 Number 且 Type(y)为String, 返回comparison x == ToNumber(y)的结果。 
        5.若Type(x) 为 String 且 Type(y)为Number, 返回比较ToNumber(x) == y的结果。 
        6.若Type(x)为Boolean, 返回比较ToNumber(x) == y的结果。 
        7.若Type(y)为Boolean, 返回比较x == ToNumber(y)的结果。 
        8.若Type(x)为String或Number,且Type(y)为Object,返回比较x == ToPrimitive(y)的结果。 
        9. 若Type(x)为Object且Type(y)为String或Number, 返回比较ToPrimitive(x) == y的结果。 
        10. 返回false。 //出自http://www.cnblogs.com/ahjesus 尊重作者辛苦劳动成果,转载请注明出处,谢谢!
        */

        function Equals(x, y) {
            if (typeof (x) == typeof (y)) {//若Type(x)与Type(y)相同, 则
                if (typeof (x) == "Undefined") {//若Type(x)为Undefined, 返回true
                    return true;
                }
                if (typeof (x) == "Null") {//若Type(x)为Null, 返回true
                    return true;
                } //出自http://www.cnblogs.com/ahjesus 尊重作者辛苦劳动成果,转载请注明出处,谢谢!
                if (typeof (x) == "Number") {//若Type(x)为Number, 则
                    if (x == NaN) {//若x为NaN, 返回false
                        return false;
                    }
                    if (y = NaN) {//若y为NaN, 返回false
                        return false;
                    }
                    if (x == y) {//若x与y为相等数值, 返回true
                        return true;
                    }
                    if (x == +0 && y == -0) {//若x 为 +0 且 y为−0, 返回true
                        return true;
                    }
                    if (x == -0 && y == +0) {//若x 为 −0 且 y为+0, 返回true
                        return true;
                    }
                    return false; //返回false
                } //出自http://www.cnblogs.com/ahjesus 尊重作者辛苦劳动成果,转载请注明出处,谢谢!
                if (typeof (x) == "String") {//若Type(x)为String, 则
                    var xChars = x.split('');
                    var yChars = y.split('');
                    var i = xChars.length;
                    while (i--) {
                        if (xChars[i] != yChars[i]) {//当x和y为完全相同的字符序列(长度相等且相同字符在相同位置)时返回true
                            return false;
                        }
                    }
                    return true; //否则, 返回false
                }
                if (typeof (x) == "Boolean") {//若Type(x)为Boolean, 则 
                    if (x && y) {//当x和y为同为true或者同为false时返回true
                        return true;
                    }

                    return false; //否则, 返回false
                }
                if (compare(a, b)) {//当x和y为引用同一对象时返回true
                    return true;
                }
                return false; //否则,返回false
            } //出自http://www.cnblogs.com/ahjesus 尊重作者辛苦劳动成果,转载请注明出处,谢谢!
            if (x == null && y == undefined) {//若x为null且y为undefined, 返回true
                return true;
            }
            if (x == undefined && y == null) {//若x为undefined且y为null, 返回true
                return true;
            }
            if (typeof (x) == "Number" && typeof (y) == "String") {//若Type(x) 为 Number 且 Type(y)为String, 返回comparison x == ToNumber(y)的结果
                return x == Number(y);
            }
            if (typeof (x) == "String" && typeof (y) == "Number") {//若Type(x) 为 String 且 Type(y)为Number, 返回比较ToNumber(x) == y的结果
                return Number(x) == y;
            }
            if (typeof (x) == "Boolean") {//若Type(x)为Boolean, 返回比较ToNumber(x) == y的结果
                return Number(x) == y;
            }
            if (typeof (y) == "Boolean") {//若Type(y)为Boolean, 返回比较x == ToNumber(y)的结果
                return x == Number(y);
            }
            if ((typeof (x) == "String" || typeof (x) == "Number") && typeof (y) == "Object") {//若Type(x)为String或Number,且Type(y)为Object,返回比较x == ToPrimitive(y)的结果
                return x == y;
            }
            if (typeof (x) == "Object" && (typeof (y) == "String" || typeof (y) == "Number")) {//若Type(x)为Object且Type(y)为String或Number, 返回比较ToPrimitive(x) == y的结果
                return x == y;
            } //出自http://www.cnblogs.com/ahjesus 尊重作者辛苦劳动成果,转载请注明出处,谢谢!
            return false; //返回false
        }
        function compare(a, b) {
            var pt = /undefined|number|string|boolean/,
                fn = /^(function\s*)(\w*\b)/,
                cr = "constructor",
                cn = "childNodes",
                pn = "parentNode",
                ce = arguments.callee;
            if (pt.test(typeof a) || pt.test(typeof b) || a === null || b === null) {
                return a === b || (isNaN(a) && isNaN(b)); //为了方便,此处假定NaN == NaN 
            }
            if (a[cr] !== b[cr]) {
                return false;
            }
            switch (a[cr]) {
                case Date:
                    {
                        return a.valueOf() === b.valueOf();
                    };
                case Function:
                    {
                        return a.toString().replace(fn, '$1') === b.toString().replace(fn, '$1'); //硬编码中声明函数的方式会影响到toString的结果,因此用正则进行格式化 
                    };
                case Array:
                    {
                        if (a.length !== b.length) {
                            return false;
                        }
                        for (var i = 0; i < a.length; i++) {
                            if (!ce(a[i], b[i])) {
                                return false;
                            }
                        }
                        break;
                    };
                default:
                    {
                        var alen = 0, blen = 0, d;
                        if (a === b) {
                            return true;
                        }
                        if (a[cn] || a[pn] || b[cn] || b[pn]) {
                            return a === b;
                        }
                        for (d in a) {
                            alen++;
                        }
                        for (d in b) {
                            blen++;
                        }
                        if (alen !== blen) {
                            return false;
                        }
                        for (d in a) {
                            if (!ce(a[d], b[d])) {
                                return false;
                            }
                        }
                        break;
                    };
            }
            return true;
        }
        function ToPrimitive(value) {
            /*
            关于ToPrimitive()方法说明:
            ToPrimitive 运算符接受一个值,和一个可选的 期望类型 作参数。ToPrimitive 
            运算符把其值参数转换为非对象类型。如果对象有能力被转换为不止一种原语类
            型,可以使用可选的 期望类型 来暗示那个类型。根据下表完成转换:

            ToPrimitive转换 
            输入类型    结果
            Undefined   结果等于输入的参数(不转换)。
            Null        结果等于输入的参数(不转换)。
            Boolean     结果等于输入的参数(不转换)。
            Number      结果等于输入的参数(不转换)。
            String      结果等于输入的参数(不转换)。
            Object      返回该对象的默认值。(调用该对象的内部方法[[DefaultValue]]一樣)。

            [[DefaultValue]] :
            对象共有的内部属性,取值范围SpecOp (Hint) → primitive
            Hint 是一个字符串。返回对象的默认值
            //出自http://www.cnblogs.com/ahjesus 尊重作者辛苦劳动成果,转载请注明出处,谢谢!
            当用字符串 hint 调用 O 的 [[DefaultValue]] 内部方法,采用以下步骤:
            1.  令 toString 为用参数 "toString" 调用对象 O 的 [[Get]] 内部方法的结果。 
            2.  如果 IsCallable(toString) 是 true,则 
                a.  令 str 为用 O 作为 this 值,空参数列表调用 toString 的 [[Call]] 内部方法的结果。 
                b.  如果 str 是原始值,返回 str。 
            3.  令 valueOf 为用参数 "valueOf" 调用对象 O 的 [[Get]] 内部方法的结果。
            4.  如果 IsCallable(valueOf) 是 true,则 
                a.  令 val 为用 O 作为 this 值,空参数列表调用 valueOf 的 [[Call]] 内部方法的结果。 
                b.  如果 val 是原始值,返回 val。 
            5.  抛出一个 TypeError 异常。 

            当用数字 hint 调用 O 的 [[DefaultValue]] 内部方法,采用以下步骤:
            1.  令 valueOf 为用参数 "valueOf" 调用对象 O 的 [[Get]] 内部方法的结果。 
            2.  如果 IsCallable(valueOf) 是 true,则 
                a.  令 val 为用 O 作为 this 值,空参数列表调用 valueOf 的 [[Call]] 内部方法的结果。 
                b.  如果 val 是原始值,返回 val。 
            3.  令 toString 为用参数 "toString" 调用对象 O 的 [[Get]] 内部方法的结果。 
            4.  如果 IsCallable(toString) 是 true,则 
                a.  令 str 为用 O 作为 this 值,空参数列表调用 toString 的 [[Call]] 内部方法的结果。 
                b.  如果 str 是原始值,返回 str。 
            5.  抛出一个 TypeError 异常

            当不用 hint 调用 O 的 [[DefaultValue]]  内部方法,O 是 Date 对象的情况下
            仿佛 hint 是字符串一样解释它的行为,除此之外仿佛 hint 是数字一样解释它的行为。
            上面说明的 [[DefaultValue]] 在原生对象中只能返回原始值。如果一个宿主对象
            实现了它自身的 [[DefaultValue]] 内部方法,那么必须确保其 [[DefaultValue]] 
            内部方法只能返回原始值。
            */
        }

 

posted on 2013-05-17 18:36  深海大虾  阅读(837)  评论(0编辑  收藏  举报