JS等価比較アルゴリズム(==)の原理について

20171 ワード

        /*        

          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]] 

                       。

            */

        }