【Javascript通识】一个==的故事

首先先给出规范关于==的逻辑,表怕,后面我会一一来解说的
在这里插入图片描述
更详细的规范请参阅ecma sec

我把上面的文字表述改为了图像,来帮助一下理解
在这里插入图片描述

看图说话

== 进行比较分为相同类型和非相同类型的比较

相同数据类型
数据类型结果
null == nulltrue
undefined == undefinedtrue
‘string’ == ‘string’true
false == falsetrue
true == truetrue
1 == 1true
+0 == -0true
NaN == NaNfalse

object类型就是看有没有指向相同的引用

真的是一看就懂,嚯嚯??

不同相同数据类型

不同数据类型的比较就比较蛋疼了???,因为会涉及隐式类型转换

string与number进行比较

string会先转换成number,‘1’ => 1, ‘s’ => NaN,数字类型的文字可以转成对应数字,非数字类型的就直接NaN,而且就像之前说的,NaN不等于任何值,自己都不等于,就是这么霸气?;

null和undefined进行比较

记住了就是true,这个是直接写在规范里面的,虽然可以死记硬背,但是规范里面还是有机可循的null & undefined这两位都代表没有可以提供的值,null == undefined -> true,但是null === undefined -> false,因为这两个值的type还是不一样的,通过Object.prototype.toString.call(null)Object.prototype.toString.call(undefined)可以看出,null的type是“[object Null]”,而undefined的type是“[object Undefined]”,所以根据严格比较符的定义,两个值将不使用隐式类型转换,直接进行值的比较,所以两个类型不一样的值进行比较肯定是false;

⚠️ null == false和undefined == false不为true 上面说了,null和undefined表示没有值,而false表示一个boolean值,叫false,所以两者是不会相等的

Boolean和其他值进行比较

Boolean与其类型值进行比较之前都会把自己转换为number类型

Object和其他类型进行比较

Object和其他类型的比较时,会试探执行toPrimitive -> valueOf -> toString这三个方法。

var obj1 = {};
obj1[Symbol.toPrimitive] = function() {
	console.log('this is in toPrimitive');
	return '2222'
};
obj1 == 2222 // true

var obj2 = {};
obj2.valueOf = function(){
	console.log('this is valueOf');
	return [];
};
obj2.toString = function() {
	console.log('this is toString');
	return false
};
obj2 == false // true
// this is valueOf
// this is toString
// true

要注意不是每个对象上面都有[Symbol.toPrimitive],比如Object,Function,Array构造函数创建的对象都没有[Symbol.toPrimitive]方法,但是Date上有

var date = new Date()
var date = new Date(2001,10,10,20,20,20,999);
console.log(date[Symbol.toPrimitive]("string")); // Sat Nov 10 2001 20:20:20 GMT+0800 (中国标准时间)
console.log(date[Symbol.toPrimitive]("number")); // 1005394820999
Symbol.toPrimitive vs valueOf vs toString

这三个方法都是在比较的时候会使用到,目的都是为了很简单,就是为了将复杂数据类型转换为原始数据类型进行比较,在用法上有以下方面需要注意:

⚠️在[Symbol.toPrimitive]方法中如果返回一个对象类型的返回值会报错,因为toPrimitive的中文就是变为原始类型,例子如下:

var a={};
a[Symbol.toPrimitive]=function(){return {}}
a[Symbol.toPrimitive]()
// Uncaught TypeError: Cannot convert object to primitive value

⚠️valueOf和toString中可以返回任何值

⚠️如果valueOf中返回的是object类型,Date,Function,Array,Object等,比较都会再使用toString方法进行比较,在使用Number, String, Boolean这些构造函数时要注意,不要使用new来构造,直接使用构造函数即可,否则返回的也是一个对象,所以不要以为new Number(), new String()出来是原始数据类型;

var a = {};
a.valueOf = function(){
	console.log("this is in valueOf");
	return new Number('2')
};
a.toString = function(){
	console.log("this is in toString");
	return '222'
}

a == '2'
// this is in valueOf
// this is in toString
// false
a == 222
// this is in valueOf
// this is in toString
// true

案例分析

我这里再举三个复(hu)杂的?

?1
[] == ![] // true

WTF,表面上看不出复杂,但是暗地里波涛汹涌,按照之前说的,任何object对象对会把自己通过toPrimitive -> valueOf -> toString的方式把自己变成一个原始类型的值,

  1. 由于[]没有toPrimitive,所以就轮到了valueOf;
  2. 由于[].valueOf()依然是[],所以轮到了toString;
  3. toString的方法是Array本身重写过的,一般如[1,2]的数组会返回"1,2",所以一个空数组的toString就是""左边已经转好了;
  4. 轮到右边,大家都知道所有object取反都是0,就是这么干脆
  5. “” == 0
  6. 任何字符串都会转换成数值和数值进行比较,所以答案很明显了toNumber("") -> 0; 0==0 ?
?2
var obj1 = {};
obj1 == 1;
// false
obj1 == "[object Object]";
// false
  1. obj 没有toPrimitive,所以由valueOf继续比较
  2. valueOf返回的{},由toString继续比较
  3. obj.toString()返回的就是"[object Object]"
?3
var date = new Date(2001,10,10,20,20,20,999);
date == "Sat Nov 10 2001 20:20:20 GMT+0800 (中国标准时间)";
// true
date == 1005394820999;
// false

这是为毛?之前我们看过例子

var date = new Date(2001,10,10,20,20,20,999);
console.log(date[Symbol.toPrimitive]("string")); // Sat Nov 10 2001 20:20:20 GMT+0800 (中国标准时间)
console.log(date[Symbol.toPrimitive]("number")); // 1005394820999

因为在进行 == 操作的时候,[Symbol.toPrimitive]方法参数是"default",所以我们可以仿造写一个简陋的Date的[Symbol.toPrimitive]方法

var Date1 = function(){}
Date1.prototype[Symbol.toPrimitive] = function(type) {
	console.log(type, ">>>")
	switch(type) {
		case "string":
			return "Sat Nov 10 2001 20:20:20 GMT+0800 (中国标准时间)";
		case "number":
			return 1005394820999;
		default: 
			console.log("execute default")
			return "Sat Nov 10 2001 20:20:20 GMT+0800 (中国标准时间)";		
	}
}

date = new Date1();
date == "Sat Nov 10 2001 20:20:20 GMT+0800 (中国标准时间)";
// default >>>
// execute default

利用上面的例子可以进一步才想==号的实现方式,以下是伪代码

if(oerator equal '==') {
	return dateInstance[Symbol.toPrimitive]("default") equal "Sat Nov 10 2001 20:20:20 GMT+0800 (中国标准时间)"
}

顺带一提关系比较符[Symbol.toPrimitive]的参数是number,参照以下例子

var date = new Date(2001,10,10,20,20,20,999);
console.log(date >= 1005394820999); //true
console.log(date < 1005394820999); // false

伪代码就是

if(oerator equal '>=') {
	return dateInstance[Symbol.toPrimitive]("number")  great than or equal to 1005394820999;
}

❤️⚡️

所以以上就是一个 == 的故事,诸君,如果不想折腾自己的话,还是用 ===号吧,之后还要说一个 ===,>= <= > < 的故事,See U next time?

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值