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]]
。
*/
}