背景
JavaScript相较于C++语言,具有更加复杂的类型,如引入了undefined、null、NaN等类型值,使得比较运算符在处理时需要较为复杂的情况,此处对其基本规律做总结,并实现简单demo。
对于运算符我们可以拆分其两块对其介绍,非相等运算符和相等运算符
相等运算符可分为,非严格相等运算符与严格相等运算符
运算规律
非相等运算符
对于非相等的比较,算法是先看两个运算子是否都是字符串,如果是的,就按照字典顺序比较(实际上是比较 Unicode 码点);否则,将两个运算子都转成数值,再比较数值的大小。
字符串比较
console.log('cat' > 'dog'); // false
console.log('cat' > 'ca'); // true
非字符串比较
原始类型值比较
转成数值比较
console.log(5>'4'); //true
// 相当于如下
console.log(Number(5) > Number('4')); //true
对象比较
对象转换成原始类型的值,算法是先调用valueOf方法;如果返回的还是对象,再接着调用toString方法
var x = [2];
x > '11' // true
// 等同于 [2].valueOf().toString() > '11'
// 即 '2' > '11'
x.valueOf = function () { return '1' };
x > '11' // false
// 等同于 (function () { return '1' })() > '11'
// 即 '1' > '11'
相等运算符
严格相等运算符
严格相等运算符首先判断是不是同一类型,再判断是否是同一值,一般大多都采用严格相等运算符
原始类型比较
console.log('1' === 1); // false
console.log('true' === true); // flase
复合类型比较
console.log({} === {}); // false
console.log([] === []); // false
上面代码分别比较两个空对象、两个空数组、两个空函数,结果都是不相等。原因是对于复合类型的值,严格相等运算比较的是,它们是否引用同一个内存地址,而运算符两边的空对象、空数组、空函数的值,都存放在不同的内存地址,结果当然是false。
非严格相等运算符
相等运算符在比较时会将其算子转换为同一类型,再利用严格相等运算符进行比较
原始类型比较
若类型不同则转为Number比较
console.log(1 == true); //true
console.log(0 == false); // true
console.log(2 == true); //true
对象值比较
对象(这里指广义的对象,包括数组和函数)与原始类型的值比较时,对象转换成原始类型的值,再进行比较。具体来说,先调用对象的valueOf()方法,如果得到原始类型的值,就按照上一小节的规则,互相比较;如果得到的还是对象,则再调用toString()方法,得到字符串形式,再进行比较。
console.log([1] == 1); // true
console.log(Number([1].valueOf().toString()) === 1);
console.log([1,2] == '1,2'); // true
console.log([1,2].toString() == '1,2');
特殊值比较
NaN比较结果均为false
console.log(NaN == NaN); // false
console.log(NaN === NaN); //fasle
console.log(NaN > NaN); // fasle
console.log(NaN < NaN); // false
undefined与null 严格与自身相等,相互比较时相等
console.log(undefined > null); //fasle
console.log(undefined < null); //fasle
console.log(undefined == null); //true
console.log(undefined === null); //false
console.log(undefined === undefined); // true
console.log(null === null); //true
总结
原始类型比较若为字符串则进行unicdoe编码比较
对象类型比较,对于非相等运算符,最终转为字符串比较,而对于相等运算符比较,则最终转为number类型比较