JavaScript==操作详解
众所周知,JavaScript中的==是一个复杂的操作,它的操作规则非常奇怪,容易让人出错,从而成为JavaScript中“最糟糕的特性”之一。
在仔细阅读了ECMAScript规范之后,我画了一幅图,我想你在理解了这幅图之后,会彻底理解关于==操作的一切。同时,我试图通过这篇文章证明==并不是那么坏的事情,它很容易掌握,甚至看似合理,并没有那么坏。
先上图:
==操作规则的确切描述在这里:抽象等式比较算法。但是,这么复杂的描述,你确定看完不会头晕吗?你确定可以马上用它来指导练习吗?
当然不是。毕竟规范是针对JavaScript运行环境的开发者(对比V8引擎的开发者),而不是针对语言用户。上图将规格翻译成便于大家查看的形式。
在详细介绍图1中的每个部分之前,让我们回顾一下JS中的类型知识:
JS中有两种类型的值:基本类型和对象类型。有五种基本类型:未定义、空、布尔、数字和字符串。未定义类型和Null类型只有一个值,即未定义和Null;布尔类型有两个值:真和假;数字类型有许多值;字符串类型的值有无限个值(理论上)。所有对象都有valueOf()和toString()方法,它们是从Object继承的,但可能被子类重写。现在考虑以下表达式:
X==y其中x和y是六种类型之一的值。
当x和y的类型相同时,X==y可以转化为x===y,后者非常简单(唯一需要注意的可能是NaN),所以我们只考虑x和y的类型不同的情况。
一、是与不是
在图1中,六种类型的JavaScript值由蓝色背景的矩形表示。首先,他们分为两组:
字符串、数字、布尔和对象(对应左边的大矩形框)未定义和空(对应右边的矩形框)的分组依据是什么?让我们看看,右边的Undefined和Null用来表示不定、无或空,而右边的四种类型分别是确定、是和非空。我们可以这样说:
左边是一个现存的世界,右边是一个空虚的世界。因此,在左右世界的任何值之间进行==比较是合理的,结果是假的。(即,在图1中连接两个矩形的水平线上标记为假)
二.空空如也
JavaScript中的Undefined和null是另一个经常让我们崩溃的地方。通常它被认为是一个设计缺陷,我们不做赘述。然而,我听说JavaScript的作者最初是这样想的:
如果打算给对象类型的值赋值,但还没有赋值,那么可以用null表示此时的状态(证据之一是typeof null的结果是‘object’);相反,如果您打算将一个变量赋给原始类型的值,但是它还没有被赋,那么您可以使用undefined来指示此时的状态。不管这个谣言是否可信,他们做一个==比较是合理的,结果是真实的。(即,在图1的右垂直线上标记为真)
在进行下一步之前,我们先来说说图1中的两个符号:大写字母N和p,这两个符号在PN部分并不代表正和负。它是:
n代表数字运算,将操作数转换成数字。它是ES规范中的一个抽象操作,但是我们可以用JS中的Number()函数来等效替换。p代表ToPrimitive操作,即将操作数转换为原始类型的值。也是ES规范中的抽象操作,也可以翻译成等价的JS代码。然而,它有点复杂。简单来说,对于一个对象,obj:obj:topprimitive(obj)相当于:首先计算obj.valueOf(),如果结果是原值就返回这个结果;否则,计算obj.toString(),如果结果是原始值,则返回结果;否则,将引发异常。注意:这里有一个例外,就是Date类型的对象会先调用toString()方法。
在图1中,用n或p标记的那一行表示,当它连接的两种类型的数据进行do==运算时,用n或p标记的那一侧的操作数应该首先执行ToNumber或ToPrimitive变换。
三.真理和谬误
从图1中可以看出,当布尔值与其他类型的值进行比较时,布尔值将被转换为数字,具体来说,
真-1假-0,没必要浪费太多口舌。好好想想。在C语言中,根本没有布尔类型。通常用来表达逻辑真理的是整数1和0。
四.字符序列
在图1中,我们将字符串和数字分成一组。为什么呢?在这六种类型中,字符串和数字是字符序列(至少字面上是这样)。字符串是所有合法字符的序列,而数字可以看作是满足一定条件的字符序列。因此,数字可以被视为字符串的子集。
根据图1,当对字符串和数字进行==运算时,需要使用ToNumber运算将字符串转换为数字。假设x是一个字符串,y是一个数字,那么:
X==y-Number(x)==y将字符串转换为数字的规则是什么?规范中的描述很复杂,但一般来说,就是去掉字符串两边的引号,看看是否能组成一个合法的数字。如果是,转换结果就是这个数;否则,结果就是NaN。例如:
number(' 123 ')//result 123 number(' 1.2e 3 ')//result 1200 number(' 123 AAC ')//result NaN当然有例外,比如将空字符串转换为数字的结果是0。也就是
数字(')//结果0
动词(verb的缩写)简单和复杂
原始类型是简单类型,简单易懂。但是缺点是表达能力有限,很难扩展,所以有对象。对象是属性的集合,属性本身可以是对象。因此,可以任意构造足够复杂的对象来表示各种事物。
但是,有时候事情复杂也不是好事。比如一篇长文,并不是每个人都有时间、耐心或者需要从头到尾读一遍,通常就足以理解大意。因此,论文有关键词和概述。JavaScript中的对象也是如此。我们需要一种方法来理解它的主要特性,所以对象有toString()和valueOf()方法。
ToString()方法用于获取对象的文本描述;valueOf()方法用于获取对象的特征值。当然,这只是我自己的理解。另外,顾名思义,toString()方法倾向于返回一个字符串。valueOf()方法?根据规范,它倾向于返回——的数字,尽管在内置类型中,valueOf()方法只返回数字和日期。
根据图1,当对象与非对象进行比较时,需要将对象转换为原始类型(虽然在与布尔类型进行比较时,需要先将布尔类型转换为数字类型,然后才需要将对象类型转换为原始类型)。这也是有道理的。毕竟==不是严格的相等比较。我们只需要拿出对象的主要特征来参与操作,而抛开次要特征。
6.一切都算数
让我们回头看看图1。内部标有n或p的线条没有方向。如果我们用箭头标记这些线,即从标记有n或p的一端到另一端的连接点,那么我们将得到(不考虑未定义和null):
你发现什么了吗?是的,在计算过程中,所有类型的值都有转化为数值类型的趋势。毕竟,一位名人曾经说过:
一切都很重要。
7.不情愿地举起一个栗子
前面废话太多了。这里举个例子证明图1确实方便有效,可以指导实践。
例如,计算以下内容:
['']==false首先,这两个操作数是对象类型和布尔类型。根据图1,需要将布尔类型转换为数值类型,将false转换为数值类型的结果为0,因此表达式变为:
['']==0两个操作数成为对象类型和数字类型。根据图1,对象类型需要转换为原始类型:
[].首先调用valueOf()。由于数组的valueOf()方法返回自身,因此结果不是原始类型。继续呼叫[]。toString()。对于数组,toString()方法的算法是将每个元素转换成一个字符串类型,然后依次用','连接,这样最后的结果就是一个空字符串'',它是原始类型的值。此时,表达式变为:
==0这两个操作数变成了字符串类型和数字类型。根据图1,字符串类型需要转换成数字类型。据说空字符串变成了数字0。然后表达式变成:
0==0到目前为止,两个操作数的类型最终是一样的,结果显然是真的。
从这个例子可以看出,为了掌握==运算的规则,除了记住图1之外,还需要记住内置对象的toString()和valueOf()方法的规则。包括对象、数组、日期、数字、字符串、布尔值等。
八.综上
前面说的一塌糊涂。这里,我们将总结图1中表示的==运算规则:
undefined==null的结果为真。与所有其他值相比,这两个值都是假的。当string==number时,字符串转换为number。布尔值==其他类型,布尔值转换为数字。当object==number/string时,对象被转换为基本类型。最后,图片被更改为仅用于娱乐:)
好了,结束了。如果你觉得这篇文章对你有用,请点赞,让更多人看到。另外,请随意指出文章中的谬误。
版权声明:JavaScript==操作详解是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。