Javascript相等性比较

JavaScript有两种比较方式:严格比较运算符和转换类型比较运算符。对于严格比较运算符(===)来说,仅当两个操作数的类型相同且值相等为true,而对于被广泛使用的比较运算符(==)来说,会在进行比较之前,将两个操作数转换成相同的类型。
对于关系运算符(比如 <=)来说,会先将操作数转为原始值,使它们类型相同,再进行比较运算。字符串比较则是使用基于标准字典的Unicode值来进行比较的, 数组也是这样比较的。

一、宽松相等(==)

比较操作符会为两个不同类型的操作数转换类型,然后进行严格比较。当两个操作数都是对象时,JavaScript会比较其内部引用,当且仅当他们的引用指向内存中的相同对象(区域)时才相等,即他们在栈内存中的引用地址相同。

  1. 类型相同的,执行===比较
  2. null == undefiend // true(特殊定义的)undefiendnull与其他对象与基础类型的值均不相等;
  3. A与数字B比较时,将A转换为数字ToNumber,若A为对象先转为原始值ToPrimitive再转为数字ToNumber;
  4. A与布尔类型B比较,将A和B转换为数字ToNumber,若A为对象先转为原始值ToPrimitive再转为数字ToNumber;
  5. A与字符串B比较,若A为数字和布尔类型,则将A和B转换为数字,若A为对象先转为原始值ToPrimitive,之后不转数字了;

非严格相等比较

ToNumber

ToNumber(A) 尝试在比较前将参数A转换为数字,这与+A(单目运算符+)的效果相同。

ToPrimitive

ToPrimitive(A)通过尝试依次调用AA.toString()参见Object.prototype.toString()A.valueOf()参见Object.prototype.valueOf()方法,将参数A转换为原始值(Primitive)。

其中,A.toString()返回 “[object type]”, A.valueOf()返回原始值。Javascript隐式装箱也是用ToPrimitive(),在Javascript只有字符串和数字才能相加。参见What is {} + {} in JavaScript?

二、一致/严格相等(===)

一致运算符不会进行类型转换,仅当操作数严格相等时返回true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var num = 0;
var obj = new String("0");
var str = "0";
var b = false;

console.log(num === num); // true
console.log(obj === obj); // true
console.log(str === str); // true

console.log(num === obj); // false
console.log(num === str); // false
console.log(obj === str); // false
console.log(null === undefined); // false
console.log(obj === null); // false
console.log(obj === undefined); // false

对于除了数值之外的值,全等操作符使用明确的语义进行比较:一个值只与自身全等。对于数值,全等操作符使用略加修改的语义来处理两个特殊情况:第一个情况是,浮点数0是不分正负的。区分+0-0在解决一些特定的数学问题时是必要的,但是大部分境况下我们并不用关心。全等操作符认为这两个值是全等的。第二个情况是,浮点数包含了NaN值,用来表示某些定义不明确的数学问题的解,例如:正无穷加负无穷。全等操作符认为NaN与其他任何值都不全等,包括它自己。(等式 (x !== x) 成立的唯一情况是 x 的值为NaN

三、Object.is (ECMAScript 2015/ ES6 新特性)

Object.is的行为方式与三等式相同,但是对于NaN-0+0进行特殊处理,所以最后两个不相同,而Object.is(NaN,NaN)将为true。(通常使用双等号或三等于将NaNNaN进行比较结果为false,因为IEEE 754如是说。)除了+0-0,其他时候避免使用Object.is,包括NaN

四、判等表

x y == === Object.is
undefined undefined true true true
null null true true true
true true true true true
false false true true true
“foo” “foo” true true true
{ foo: “bar” } x true true true
0 0 true true true
+0 -0 true true false
0 false true false false
“” false true false false
“” 0 true false false
“0” 0 true false false
“17” 17 true false false
[1,2] “1,2” true false false
new String(“foo”) “foo” true false false
null undefined true false false
null false false false false
undefined false false false false
{ foo: “bar” } { foo: “bar” } false false false
new String(“foo”) new String(“foo”) false false false
0 null false false false
0 NaN false false false
“foo” NaN false false false
NaN NaN false false true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// true 两个操作数均为String
'foo' === 'foo'

var a = new String('foo');
var b = new String('foo');

// false a,b对象引用不同
a == b

// false a,b均为对象,但是引用不同
a === b

// true 操作数类型不同,对象a转换为String类型
a == 'foo'

五、参见

==比较表

js比较表


if()比较表(2017.8.6新增)

if比较表

Javascript比较表

参考文献

  1. MDN比较运算符
  2. MDN相等性比较
  3. ECMAScript官方文件
  4. js比较表
  5. ECMAScript ToPrimitive
  6. object原始值
  7. What is {} + {} in JavaScript?