1.先了解一下基本类型和复杂类型划分的依据

JS中的值有两种类型:原始类型(Primitive)、对象类型(Object)。原始类型包括:Undefined、Null、Boolean、Number和String等五种。这两大类别的数据存储方式是不一样的。

存储空间的时空关系可以概括为空间大,访问起来就慢,反之亦然。堆比栈大,栈比堆的运算速度快,

对象是一个复杂的结构,并且可以自由扩展,如:数组可以无限扩充,对象可以自由添加属性。将它们放在堆中是为了不影响栈的效率。而是通过引用的方式查找到堆中的实际对象再进行操作。

相对于对象类型而言,原始类型就比较稳定,并且它只占据很小的内存。不将原始类型放在堆是因为通过引用到堆中查找实际对象是要花费时间的,而这个综合成本远大于直接从栈中取得实际值的成本。所以简单数据类型的值直接存放在栈中。`

顺带说一下undefined和null的使用区别:

假如你打算把一个变量赋予对象类型的值,但是现在还没有赋值,那么你可以用null表示此时的状态(证据之一就是typeof null 的结果是'object');相反,假如你打算把一个变量赋予原始类型的值,但是现在还没有赋值,那么你可以用undefined表示此时的状态。

2.进行==比较时数据的转换规则

==运算规则的准备描述如下:

看完之后有没有感觉有点脑壳疼,这样的描述很难让人在实践中使用,所以很有必要对上述规则进行简化概括:

  • undefined == null,结果是true。且它俩与所有其他值比较的结果都是false。

  • String == Boolean,需要两个操作数同时转为Number。

  • String/Boolean == Number,需要String/Boolean转为Number。

  • Object == Primitive,需要Object转为Primitive(具体通过valueOf和toString方法)。

那么Boolean,Number,Primitive的转换规则是:

(1)其它类型转换成Boolean的规则是:

(2)其它类型转换成Number类型的规则

object类型一般要先转换成string类型,接着才进行Number类型的转换。字符串转化为数字的规则规范中描述得很复杂,但是大致说来,就是把字符串两边的空白字符去掉,然后把两边的引号去掉,看它能否组成一个合法的数字。如果是,转化结果就是这个数字;否则,结果是NaN。

Number('123') // 结果123
Number('1.2e3') // 结果1200
Number('123abc') // 结果NaN
Number('\r\n\t123\v\f') // 结果123

当然也有例外,比如空白字符串转化为数字的结果是0。即:

Number('') // 结果0
Number('\r\n\t \v\f') // 结果0
需要补充说明的是:
(3)对象类型向primitive类型转换的规则是:

为什么要区分原始类型和复杂类型?

原始类型是一种单纯的类型,它们直接了当、容易理解。然而缺点是表达能力有限,难以扩展,所以就有了对象。对象是属性的集合,而属性本身又可以是对象。所以对象可以被构造得任意复杂,足以表示各种各样的事物。

  但是,有时候事情复杂了也不是好事。比如一篇冗长的论文,并不是每个人都有时间、有耐心或有必要从头到尾读一遍,通常只了解其中心思想就够了。于是论文就有了关键字、概述。JavaScript中的对象也一样,我们需要有一种手段了解它的主要特征,于是对象就有了toString()和valueOf()方法。

这两种方法的区别是:

toString()方法用来得到对象的一段文字描述;而valueOf()方法用来得到对象的特征值。

   toString()方法倾向于返回一个字符串。valueOf()方法倾向于返回一个数字——尽管内置类型中,valueOf()方法返回数字的只有Number和Date。


对于所有非日期对象来说,对象到原始值的转换基本上是对象到数字的转换

  一般来说,对象到数字的转换经过了如下过程:

  1.如果对象具有valueOf()方法,后者返回一个原始值,则js将这个原始值转换成数字,并返回这个数字。

  2.否则,如果对象具有toString()方法,后者返回一个原始值,则js将转换并返回。(首先js转换成相应的字符串原始值,再继续将这个原始值转换成相应的数字类型,再返回数字)

  3.否则,js抛出一个类型错误异常。

  一般来说,对象到字符串的转换经过了如下步骤:

  1.如果对象具有toString()方法,则调用这个方法。如果它返回一个原始值,js将这个值转换成字符串,并返还这个字符串结果。

  2.如果对象没有toString()方法,或者toString并不返回一个原始值,那么js将调用valueOf()方法。

  3.否则,js无法从toString()或者valueOf()获得一个原始值,因此这时它将抛出一个类型错误异常。

   
下图第一列和第二列是其它类型调用toString方法时的转换规则

需要说明的是: toString方法会将{}转换成"[object Object]",将function(){}转换成"function(){}"

其它类型调用valueOf方法的转换规则是:

  

经过层层深入剖析,现在你应该理解前面各种数据类型进行 == 运算时的隐式运作规则了吧。现在再碰到如下的问题,是不是感觉思路很清晰

[]==[]             //false
[]==![] //true
{}==!{} //false 实际上被解析成 { ' } == !{ ' }
{}==![] //Uncaught SyntaxError: Unexpected token == 表达式不能以{开头 {}是个语句块,后面跟== ![]就变成了一种语法错误的语句块
// 在语法解析的时候,如果一个语句以「{」开头,就只把它解释成语句块。换用形式语法的说法,就是「表达式语句不能以『{』开头」。对表达式语句开头的另一个限制——限制「function」出现在开头——同理
![]=={} //false
[]==!{} //true
undefined==null //true
[]  == []  // false 因为它们的引用地址不一样

由上面的比较可以得出:
对任何一种类型进行取反 会得到一个boolean类型的值
[]在与不同的类型对比的时候,会转换成0
{}在与不同的类型对比的时候,会转换成NaN,
不同类型的比较最终都被转换成number类型的比较 参考文章 [1]
一张图彻底搞懂JavaScript的==运算

[2] 为什么控制台打印{}+[]===[]+{}为false?

 

js == 运算规则解析的更多相关文章

  1. JS的解析与执行过程

    JS的解析与执行过程 全局中的解析和执行过程 预处理:创建一个词法环境(LexicalEnvironment,在后面简写为LE),扫描JS中的用声明的方式声明的函数,用var定义的变量并将它们加到预处 ...

  2. JS的解析机制

    JS的解析机制,是JS的又一大重点知识点,在面试题中更经常出现,今天就来唠唠他们的原理.首先呢,我们在我们伟大的浏览器中,有个叫做JS解析器的东西,它专门用来读取JS,执行JS.一般情况是存在作用域就 ...

  3. js的解析--预处理(三)

    js的解析与执行过程  分全局  {预处理阶段和执行阶段}  函数{预处理函数和执行阶段}   1/创建词法环境(环境上下文) LexicalEnvironment   === window { } ...

  4. [妙味JS基础]第六课:作用域、JS预解析机制

    知识点总结 浏览器的解析方法 script 全局变量,全局函数 自上而下 函数 由里到外 "JS的解析器": 1)“找一些东西”:var function 参数 var a=未定义 ...

  5. js字符串转日期,js字符串解析成日期,js日期解析, Date.parse小时是8点,Date.parse时间多了8小时

    js字符串转日期,js字符串解析成日期,js日期解析, Date.parse小时是8点,Date.parse时间多了8小时 >>>>>>>>>&g ...

  6. json进阶(一)js读取解析JSON类型数据

    js读取解析JSON类型数据 一.什么是JSON? JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,是理想的数据交换格式,同 ...

  7. js读取解析JSON类型数据【申明:来源于网络】

    js读取解析JSON类型数据[申明:来源于网络] 地址:http://blog.csdn.net/sunhuaqiang1/article/details/47026841

  8. Js引擎解析执行 阅读笔记

    Js引擎解析执行 阅读笔记 一篇阅读笔记 http://km.oa.com/group/2178/articles/show/145691?kmref=search&from_page=1&a ...

  9. javaScript 变量提升 var let const,以及JS 的解析阶段和执行阶段

    我们先来看一道面试题,大家猜想一下,下面这段代码,打印出来的结果是什么 var name = 'World!'; (function () { if (typeof name === 'undefin ...

随机推荐

  1. 使用SpringSecurity体验OAUTH2之一 (入门1)

    OAUTH2是一种安全的授权框架,其原理在网上有许多文章上可以看到.但从实践角度,好的文章比较少.SpringSecurity框架本身是支持OAUTH2的,所以下面通过使用SpringSecurity ...

  2. unity 屏幕适配的问题

    首先是AB的加载时,会出现localscale的改变,需要在初始化时将其调节为1.0并且 offmax和min都设置为0,此时方才会出现在自己臆想之中(尤其是需要设置父节点时)

  3. iOS unity 互相调用加载高德地图时

    需要增加 mapView.delegate = self 这是一种设计模式,有的人称为代理,有的人称为委托,比如有A,B两个控制器,由A可以push到B,B可以pop回A,现在有一种情况,A中有一个l ...

  4. javascript中new Date()存在的兼容性问题

    问题:通过new Date()创建的时间对象在Chrome能正常工作,但在IE浏览器却显示NaN 代码: var time = new Date(date + ' 00:00:00'); //NaN ...

  5. Nginx+IIS+asp.net mvc 实现负载均衡示例

    一.Nginx官网 http://nginx.org/ 二.下载并安装Nginx 下载地址:http://nginx.org/en/download.html 启动Nginx,启动成功的话可以在任务管 ...

  6. 认识uWSGI、uwsgi、wsgi

    WSGI协议 首先弄清下面几个概念: WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web ...

  7. 解决问题SyntaxError: Unexpected token import

    ES6语法的模块导入导出(import/export)功能,我们在使用它的时候,可能会报错: SyntaxError: Unexpected token import 语法错误:此处不应该出现impo ...

  8. Oracle数据库体系结构之进程结构(4)

    Oracle进程结构包括用户进程,服务进程,后台进程. 1. 用户进程 用户进程在数据库用户要求连接到Oracle服务器时开始启动. 用户进程是要求Oracle服务器交互的一种进程 它必须首先建立一个 ...

  9. [奇思异想]使用Zookeeper管理数据库连接串

    背景 有一套特定规格的应用(程序+数据库),当有业务需求时,就需要多部署应用,并且所有的应用都使用一个共同的后台来管理.应用新增后,如何通知后台更新连接串成了一个关键的问题.于是就产生了使用ZooKe ...

  10. vs2013下配置x64版c++

    最近在ddctf的比赛遇到了x64版的逆向,一大堆寄存器调试的头昏,然后比赛结束后在自己电脑上配置下x64版的c++环境记录下: 首先我们需要新建项目不再废话,然后选择:debug->配置管理器 ...