js比较
基本转换
你不知道的javascript中卷4.2
ToNumber
- ToNumber 其中 true转换为1,false转换为0。undefined转换为NaN,null转换为0
为了将值转换为相应的基本类型值,抽象操作ToPrimitive 会首先(通过内部操作DefaultValue)检查该值是否有valueOf() 方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有,就使用toString()的返回值(如果存在)来进行强制转换
如果valueOf()和toString()均不返回基本类型值,会产生TypeError错误。
从ES5开始,使用Object.create(null)创建的对象[[Prototype]]的属性为null,并且没有valueOf(),toString()方法,因此无法进行强制类型转换。
ToBoolean
- 假值
1.1. 可以被强制类型转换为false的值
1.2 其他(被强制类型转换为true的值)
以下这些是假值: undefined,null,‘’, +0/-0和NaN,false
加值的布尔强制类型转换结果为false。
理论上所有假值意外的值都是真值 - 假值对象
var a = new Boolean(false); var b = new Number(0); var c = new String(''); // 以上是封装了假值的对象,均为true
document.all
,是一个类数组对象,包含来所有元素,之前为true,现在为false - 真值
真值就是假值列表以外的值
var a = 'false';
var b = '0';
var c = "''";
var d = Boolean(a && b && c)
d; // true
var a = [];
var b = {};
var c = function () {};
var d = Boolean(a&& b&& c);
d; // true
特殊的函数
- Function 重写了 toString()
- Date 重写了 toString() 也重写了 valueOf()
- Array 重写了 toString()
toString()
// Function
let fn = function () {}
console.log(fn == 'function () {}') //true
// 先转为valueOf,再把它转为toString(),
let fn = function () {}
console.log(fn == 'function () {}') //false
// Array
let arr = [1,2,3,4,5,2,1,5,2,1,5]
console.log(arr == '1,2,3,4,5,2,1,5,2,1,5')//true
// Date
let date = new Date('2020-08-12')
console.log(date == 'Wed Aug 12 2020 08:00:00 GMT+0800 (中国标准时间)')//true
// Object
let obj1 = {},obj2 = {name:'name'}
console.log(obj2 == '[object Object]')//true
valueOf
let fn = function () {}
console.log(fn.valueOf() === fn)//true
let arr = [1,2,3,4,5,2,1,5,2, 1,5]
console.log(arr.valueOf() === arr)//Array也是返回自身
let obj = {}
console.log(obj.valueOf() === obj)//Object也是返回自身
let date = new Date('2020-08-12')
console.log(date.valueOf() === date)//false
let date = new Date('2020-08-12')
console.log(date.valueOf() === 1597190400000 )//true
// 返回的是从 1970 年 1 月 1 日午夜开始计的毫秒数。
宽松相等(loose equals)== 和严格相等(strict equals)===
==
允许在相等比较中进行类型转换,而===
不允许
相等比较操作都性能
==
需要强制类型转换(仅仅微秒级差别)百万分之一秒
字符串和数字直接比较
var a = 42;
var b = '42';
a === b; // false
a == b; // true
因为没有强制类型转换,所以a===b`` 为false, 42和“42不相等”
a == b`是宽松相等,即如果两个值的类型不同,则对其中之一或两者都进行强制类型转换;
具体转换规则
- a是数字,b是字符串,则b转换为数字进行比较
- a是字符串,b是数字,则a转换为数字进行比较
其他类型和布尔值之前相等比较
var a = '42';
var b = true;
a == b; // false
具体转换规则
- 如果a是布尔类型,则a转换为数字进行和b比较
- 如果b是布尔类型,则b转换为数字进行和a比较
以上分析可得,先将b转换为数字,Number(b) 为1,变成
‘42’ === 1
,两者类型仍然不同,‘42’根据规则被强制类型转换为32,最后变成1 == 42
,结果为false;b如果为true,结果仍为false;
var a = '42'
// 不要这样用,条件判断不成立
if (a === true) {
//..
}
// 也不要这样用,条件判断不成立
if (a === true){
}
// 这样的显式用法没问题
if (a){}
// 这样显示用法更好
if (!!a) {}
// 这样显式用法也好
if(Boolean(a)){}
null和undefined直接的相等比较
- 如果x为null,y为undefined,结果为true;
- 如果x为undefined,y为null,结果为true;
在==
中null和undefined相等(它们也与自身相等,除此之外其他值都不存在这种情况);
var a = null;
var b;
a == b; // true
a == null; // true
b == null; // true
// 以下为false
a == false;
b == false;
a == '';
b == '';
a == 0;
b == 0
对象和非对象之间的相等比较
- 如果x是字符串或数字,y是对象,测返回 x == ToPrimitive(y)的结果
- 如果y是字符串或数字,x是对象,测返回 ToPrimitive(x) === y的结果
- 这里只提到了字符串和数字,没有布尔值。原因是布尔值会被强制类型转换为数字
var a = 42;
var b = [42];
a == b; // true
[42]首先调用ToPrimitive抽象操作,返回“42”,变成“42” == 42, 然后变成 42 == 42 ,最后两者相等
var a = 'abc';
var b = Object(a);// 和new String(a)一样
a === b; // false
a == b; // true
a == b 结果为true,因为b通过ToPrimitive进行强制类型转换(也称为“拆封”),并返回标量基本类型“abc”, 与a相等。
但有些值不这样,原因是== 算法中其他优先级更高的规则,例
var a = null;
var b = Object(a); // 和Object()一样
a == b // false
var c = undefined;
var d = Object(c); // 和Object() 一样
c == d; // false
var e = NaN;
var f = Object(e) // 和new Number(e)一样
e == f; // false
因为没有对应的封装对象,所以null和undefined不能够被封装,Object(null)和Object()均返回一个常规对象。
NaN能够被封装为数字封装对象,但NaN == NaN返回false
特殊情况
- 自定义返回其他数字
- 假值的相等比较
'0' == null // false
'0' == undefined // false
'0' == false; // ---true
'0' == NaN; // false
'0' == 0; // true
'0' == ""; // false
false == null // false
false == undefined // false
false == NaN; // false
false == 0; // ------true
false == ''; // ---true
false == []; // ----true
false == {}; // false
0 == null // false
0 == undefined // false
0 == NaN; // false
0 == []; // ----true
0 == {}; // false
- 极端例子
[] == ![]
2 == [2];
'' == [null];
0 == '\n'
// ToNumber强制类型转换为0的有 '', '\n'
安全运用隐式强制类型转换
- 如果两边的值中有true或者false,千万不要使用==
- 如果两边的值中有[]’'或者0,尽量不要使用==。
抽象关系比较
var a = [42];
var b = ["43"];
a > b // false
var a = ['42'];
var b = ['043'];
a > b // true
var a = [4,2];
var b = [0, 4, 3];
a > b // true
var a = {b: 42};
var a = {b: 43};
a < b; // false
// a为[object Object], b为[object Object],所以按字母顺序a<b 不成立
a < b; // false
a > b; // false
a == b; // false
a <= b; // true 意思为不大于 a< b false; <= 为翻转,就为true;
a >= b; // true 意思为不大于
// 为避免这种情况,比较时应该为同一类型
- 小结
[] + {}; // "[object Object]"
{} + []; // 0
第一种:数组被强制转换类型转为’’,对象被强制转换类型转为“[object Object]”,空字符串和“[object Object]”相加为“[object Object]”
第二种 ,{}被当作独立的空代码块,不执行任何操作;代码块结尾不需要分号,所以不存在语法上的问题;最后+[],将显式强制转换为0,所以输出0