有段代码如下:
![] == [],true or false?
我们都知道,ECMAScript中有两种类型的相等操作符:
- 全等与不全等——直接比较而不转换类型
- 相等与不相等——先转换类型再比较
全等与不全等的逻辑比较简单,而今天我们要关注的是我们平时用得比较多的第二种操作符:相等与不相等。当我们对两个操作数用 == 进行比较的时候,我们分两种情况:== 两边操作数的类型相同与不相同。我们都知道类型不相同时需要先转换类型,但是其中的转换规则是什么样的呢?也许许多人都不曾仔细研究过,今天我们就通过分析![] == []来深入研究一下 == 的比较机制。
两边类型相同
当两边的类型相同时,比较的逻辑就跟 === 一样:
- 如果类型都是基本类型,则直接比较其值
- 如果都是引用类型,则比较其引用地址(是否指向同一个对象)
如以下代码:
1 |
console.log(5 == 5); //true |
2 |
console.log('abc' == 'abc'); //true |
3 |
console.log([] == []); //false,两个不同的引用地址 |
5 |
console.log(a == b); //true |
也许有人会说,既然[] == []为false,那么前面那个![] == []的结果就是true咯?!没错,但是其中的判断逻辑不是这么简单的,因为![]等于false,所以这个比较就相当于false == [],这时两边的类型不一样的,一个是Boolean,一个是Array,所以我们不能简单通过[] == []为false来判断![] == []为true,当我们将[]换成{},这时结果就不一样了。
1 |
console.log([] == []); //false |
2 |
console.log(![] == []); //true |
3 |
console.log({} == {}); //false |
4 |
console.log(!{} == {}); //false |
也许你会感到糊涂,[]与{}同样是引用类型,为什么![] == []与!{} == {}的结果不一样呢?那是因为Array有其特殊的地方,这时后话,我们先来看下当 == 两边类型不相等时的转换规则。
两边类型不相同
当 == 两边操作数的类型不相同时,会将操作数的类型进行转换相同的类型,通常也叫强制转型,然后再比较其相等性,比如:
1 |
console.log(5 == '5'); //true,将字符'5'转换成数字5再比较 |
2 |
console.log(false == 0); //true,先将布尔值false转换成数字0 |
在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:
- 如果有一个操作数是布尔值,则在比较相等性之前现将其转换成数值——false转换成0,而true转换成1
- 如果一个操作数是字符串,另外一个操作数是数值,在比较相等性之前现将其转换成数值(用Number()方法)
- 如果一个操作数是对象(引用类型),另外一个操作数不是,则调用对象的valueOf()方法,用得到的原始值按照前面的规则进行比较(如果得到的原始值还是对象,则调用原始值的toString()方法再进行比较)
另外有几个需要注意的地方:
- null和undefined是相等的(undefined派生于null)
- 要比较相等性之前,不能将null和undefined转换成其他值(即除null和undefined之外的值都不和null与undefined相等)
- 一般来说,如果a == b为true的话,那么a != b即为false,反之也可行,但是有一个例外,那就是NaN,NaN不等于任何操作数,包括它自己,即NaN == NaN和NaN != NaN都为false
根据以上规则,我们可以自己写一个比较相等的函数:
01 |
function Equal(a, b) { |
02 |
var typeA = typeof a, typeB = typeof b; |
04 |
//如果有一个操作数是NaN,则总返回false |
05 |
//isNaN(undefined)返回true |
06 |
if ((isNaN(a) && typeA === 'number') || (isNaN(b) && typeB === 'number')) { return false; } |
08 |
//如果操作数类型相等,则比较它们的值,否则转换类型 |
09 |
if (typeA === typeB) { |
12 |
//将undefined转成null(实际上是不转的,此处只是方便后面的比较) |
13 |
if (typeA === 'undefined') { a = null; } |
14 |
if (typeB === 'undefined') { b = null; } |
16 |
if (a === null || b === null) { |
18 |
} else if (typeA === 'object' || typeB === 'object') { |
20 |
//先调用其valueOf方法,如果返回还是object,则调用其toString方法 |
21 |
var o = (typeA === 'object' ? a : b).valueOf(), other = o === a ? b : a; |
22 |
if (typeof o === 'object') { |
25 |
return Equal(o, other); |
27 |
//如果有Boolean,将其转成Number |
28 |
if (typeA === 'boolean') { a = a ? 1 : 0; } |
29 |
if (typeB === 'boolean') { b = b ? 1 : 0; } |
30 |
//如果其中一个类型是Array,另外一个是Number,Number()返回number或NaN |
31 |
if (typeA === 'string' && typeB === 'number') { a = Number(a); } |
32 |
if (typeB === 'string' && typeA === 'number') { b = Number(b); } |
37 |
console.log(Equal([], [])); //false |
38 |
console.log(Equal(![], [])); //true |
39 |
console.log(Equal({}, {})); //false |
40 |
console.log(Equal(!{}, {})); //false |
41 |
console.log(Equal(NaN, NaN)); //false |
42 |
console.log(Equal(undefined, null)); //true |
43 |
console.log(Equal(false, null)); //false |
44 |
console.log(Equal(false, 0)); //true |
45 |
console.log(Equal(true, 2)); //false |
Array.toString()
那么为什么![] == []为true呢?其比较步骤如下:
- ![]为false,式子相当于false == [],两边类型不同且有一个对象[]
- 右边的[]调用valueOf()方法,得到的还是对象[],因此再调用toString()的方法,Array的toString()方法相当于Array.join(','),例如[1, 2, 3].toString()等于'1,2,3',而[].toString()等于一个空字符串''({}.toString()等于'[object Object]'),则此时式子相当于false == ''
- 因为存在布尔值为false,将其转成数值0,此时式子变成0 == ''
- 最后将右边的空字符串''用Number()方法转成0,0 == 0为true,所以![] == []
因此:
1 |
console.log(![] == []); //true |
2 |
console.log(0 == []); //true |
3 |
console.log(0 == ['']); //true |
4 |
console.log('0' == []); //false |
5 |
console.log('0' == [0]); //true |
6 |
console.log(true == [1]); //true |
总结:由于相等和不相等操作符存在类型转换问题,而为了保持代码中数据类型的完整性,推荐使用全等和不全等操作符(已经强调很久了)。
- JavaScript自动计算价格和全选
JavaScript自动计算价格和全选,价格自增加减,复选框,反选,全选. 如图: 如图: CSS代码 @charset "gb2312"; /* CSS Document */ ...
- javascript小技巧(非常全)
事件源对象 event.srcElement.tagName event.srcElement.type 捕获释放 event.srcElement.setCapture(); event.srcE ...
- Javascript实现CheckBox的全选与取消全选的代码(转)
js函数 复制代码 代码如下: <script type="text/javascript"> function checkAll(name) { var el = d ...
- JavaScript案例四:全选练习
JavaScript实现全选,全不选等效果... <!DOCTYPE html> <html> <head> <title>JavaScript全选练习 ...
- (网页)javascript小技巧(非常全)
事件源对象 event.srcElement.tagName event.srcElement.type 捕获释放 event.srcElement.setCapture(); event.srcE ...
- JavaScript -- 操作input CheckBox 全选框
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- JavaScript:让浏览器全屏显示
并不是所有人都会按F11让浏览器全屏显示~~~ 一.直接上代码 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xh ...
- Javascript与Flash通信全解析
原文:https://www.imququ.com/post/39.html Flash已经提供了ExternalInterface接口与JavaScript通信,ExternalInterface有 ...
- JavaScript基础篇最全
本章内容: 简介 定义 注释 引入文件 变量 运算符 算术运算符 比较运算符 逻辑运算符 数据类型 数字 字符串 布尔类型 数组 Math 语句 条件语句(if.switch) 循环语句(for.fo ...
- JavaScript数组所有API全解密
全文共13k+字,系统讲解了JavaScript数组的各种特性和API. 数组是一种非常重要的数据类型,它语法简单.灵活.高效. 在多数编程语言中,数组都充当着至关重要的角色,以至于很难想象没有数组的 ...
随机推荐
- 什么是高防服务器?如何搭建DDOS流量攻击防护系统
关于高防服务器的使用以及需求,从以往的联众棋牌到目前发展迅猛的手机APP棋牌,越来越多的游戏行业都在使用高防服务器系统,从2018年1月到11月,国内棋牌运营公司发展到了几百家. 棋牌的玩法模式从之前 ...
- 网站如何防止sql注入攻击的解决办法
首先我们来了解下什么是SQL注入,SQL注入简单来讲就是将一些非法参数插入到网站数据库中去,执行一些sql命令,比如查询数据库的账号密码,数据库的版本,数据库服务器的IP等等的一些操作,sql注入是目 ...
- C语言结构体的学习,以及gdb的调式
#include <stdio.h> #include <string.h> #define format "%d\n%s\n%f\n%f\n%f\n" t ...
- CSS3新特性回顾
CSS3 介绍 开始实例 新特征简介 强大的CSS选择器 抛弃图片的视觉效果 盒模型变化(多列布局和弹性盒模型) 阴影效果 Web字体和web Font 图标 CSS33过渡与动画交互效果 媒体查询 ...
- Union-find 并查集
解决问题 给一系列对点0~N-1的连接,判断某两个点p与q是否相连. private int[] id; // 判断p和q是否属于同一个连通分量 public boolean connected(in ...
- Qt 实现脉搏检测-1-心跳曲线部分
最新的想法就是写一个显示脉搏的东西,主要就是通过串口读取硬件(检测心跳的)传来的数据,在显示一下. 先实现画心跳曲线 如下图 先来电干货, 首先,在这个代码中,第一次用到了list这个东东 所以,关于 ...
- C++学习005-循环
C++在循环方面,感觉个C没有身边么区别 while循环 for循环 do while循环 其实 使用Goto也可以写个循环 编写环境vs2015 1. while循环 int main() { in ...
- MySQL☞聚合函数/分组函数
分组函数(聚合函数) 1.count(*/列名): a.*:求出该数据的总条数 select count(*) from 表名 b.列名:求出该列中列名不为null的总条数 select cou ...
- [推荐]spring cloud 详解
http://blog.csdn.net/column/details/15197.html
- 问题 C: 质因数的个数
1947: 质因数的个数 时间限制: 1 Sec 内存限制: 32 MB提交: 245 解决: 114[提交][状态][讨论版][命题人:外部导入] 题目描述 求正整数N(N>1)的质因数的 ...