5.5 关系运算符
关系运算符也称为比较运算符,它反映了运算数之间关系的一类运算,因此这类运算符一般都是二元运算符,关系运算返回的值总是布尔值。
5.5.1 大小比较
基本大小关系的比较运算,以及对应运算符说明如表5-7所示。
表5-7 基本比较运算
比较运算中的运算数不局限于数值,可以是任意类型的数据。但是在执行运算时,它主要根据数值的大小,以及字符串中字符在字符编码表中的位置值来比较大小。所以对于其他类型的值,将会被转换为数字或字符串,然后再进行比较。
【示例】在比较运算中,运算数的转换操作规则说明如下。
如果运算数都是数字,或者都可以被转换成数字,则将根据数字大小进行比较。
alert(4>3); //返回true,直接利用数值大小进行比较 alert("4">Infinity); //返回false,无穷大比任何数字都大
但是对于下面代码来说,就比较特殊了。两个运算数虽然都可以被转换为数字,但是由于它们都是字符串,则不再执行数据类型转换,而是直接根据字符串进行比较。
alert("4">"3"); //返回true,以字符串进行比较,而不是数字大小进行比较
如果运算数都是字符串,或者都被转换为字符串,那么将根据字符在字符编码表中的位置大小进行比较。同时字符串是区分大小写的,因为大小写字符在表中的位置不同。一般小写字符大于大写字符。如果比较中不区分大小写,则建议使用toLowerCase()或toUpperCase()方法把字符串统一为小写或大写形式。
alert("a">"b"); //返回false,字符a编码为61,字符b编码为62 alert("ab">"cb"); //返回false, c的编码为63。从左到右对字符串中对应字符逐个进行比较 alert("abd">"abc"); //返回true, d的编码为64。前面字符相同,则比较下一个字符
如果一个运算数是数字,或者被转换为数字,另一个是字符串,或者被转换为字符串,则比较运算符调用parseInt()将字符串强制转换为数字,不过对于非数字字符串来说,将被转换为NaN值,最后以数字方式进行比较。运算数是NaN,则比较结果为false。
alert("a">"3"); //返回true,字符a编码为61,字符3编码为33 alert("a">3); //返回false,字符a被强制转换为NaN
如果运算数都无法转换为数字或字符串,则比较结果为false。
如果一个运算数为NaN,或者被转换为NaN,则始终返回false。
如果对象可以被转换为数字或字符串,则执行数字或字符串比较。
5.5.2 案例:包含检测
in运算符能够判断左侧运算数是否为右侧运算数的成员。其中左侧运算数应该是一个字符串,或者可以转换为字符串。右侧运算数则应该是一个对象或数组。
【示例1】下面的代码演示了如何利用in运算符检测属性a、b、c、valueOf是否为对象o的成员。
var o={ //定义对象结构 a:1, //定义对象的属性a b:function(){} //定义对象的方法b } alert("a"in o); //返回true alert("b"in o); //返回true alert("c"in o); //返回false alert("valueOf"in o); //返回true,继承JavaScript为所有Object对象定义的方法 alert("constructor"in o); //返回true,继承JavaScript为所有Object对象定义的属性
使用instanceof运算符检测对象实例是否属于某个类或构造函数。其中instanceof运算符左侧运算数是对象实例名,右侧运算数是类名或构造器名。
【示例2】下面的代码演示了如何使用instanceof运算符检测数组a是否为Array、Object和Function的实例。
var a=new Array(); //定义变量a为构造函数Array的一个对象实例 alert(a instanceof Array); //返回true alert(a instanceof Object); //返回true,所有对象都是Object类的实例 alert(a instanceof Function); //返回false
如果左侧运算数不是对象,或右侧运算数不是类或构造函数,则将返回false。如果右侧运算数不是对象,则将返回错误。
5.5.3 案例:等值检测
JavaScript提供了4个等值检测运算符:全等(===)和不全等(! ==)、相等(==)和不相等(! =)。详细说明如表5-8所示。
表5-8 等值运算
在相等运算中,一般遵照如下基本规则进行比较:
如果运算数是布尔值,在比较之前先转换为数值。其中false转换为0, true转换为1。
如果一个运算数是字符串,另一个运算数是数字,在比较之前先尝试把字符串转换为数字。
如果一个运算数是字符串,另一个运算数是对象,在比较之前先尝试把对象转换为字符串。
如果一个运算数是数字,另一个运算数是对象,在比较之前先尝试把对象转换为数字。
如果两个运算数都是对象,那么比较它们的引用值(引用地址)。如果指向同一个引用对象,则相等,否则不等。
【示例1】下面是一些特殊运算数的比较。
alert("1"==1) //返回true。字符串被转换为数字 alert(true==1) //返回true。true被转换为1 alert(false==0) //返回true。false被转换为0 alert(null==0) //返回false alert(undefined==0) //返回false alert(undefined==null) //返回true alert(NaN=="NaN") //返回false alert(NaN==1) //返回false alert(NaN==NaN) //返回false alert(NaN! =NaN) //返回true
NaN与任何值都不相等,包括它自己。null和undefined值相等,但它们是不同类型的数据。在相等比较中,null和undefined是不允许被转换为其他类型的值。
【示例2】下面两个变量的值虽然是通过计算得到,但它们的值是相等的。
var a = "abc" + "d"; var b = "a" + "bcd"; alert(a==b); //返回true
对于值类型的数据而言,数值和布尔值的相等比较运算效果比较高,但是字符串需要消耗大量资源,因为字符串需要逐个字符进行比较,才能够确定它们是否相等。
在全等运算中,一般遵照如下基本规则进行比较:
如果运算数都是值类型,则只有数据类型相同,且数值相等时才能够相同。
如果一个运算数是数字、字符串或布尔值(值类型),另一个运算数是对象等引用类型,则它们肯定不相同。
如果两个对象(引用类型)比较,则比较它们的引用地址。
【示例3】下面是特殊运算数的全等比较。
alert(null===undefined) //返回false alert(0==="0") //返回false alert(0===false) //返回false
【示例4】下面是两个对象的比较,由于它们都引用相同的地址,所以返回true。
var a = {}; var b = a; alert(a===b); //返回true
但是对于下面两个对象来说,虽然它们的结构相同,由于地址不同,所以也不全等。
var a = {}; var b = {}; alert(a===b); //返回false
【示例5】对于引用类型的值进行比较,主要比较引用的地址是否相同,而不是比较它们的值。
var a=new String("abcd") //定义字符串"abcd"对象 var b=new String("abcd") //定义字符串"abcd"对象 alert(a===b); //返回false alert(a==b); //返回false
在上面示例中,两个对象的值相等,但是它们的引用地址不同,所以它们既不相等,也不全等。事实上,对于引用类型的值来说,相等(==)和全等(===)运算符操作的结果是相同的,没有本质区别。
【示例6】对于值类型而言,只要类型相同,值相等,它们就应该完全全等,这里不需要考虑比较运算数的表达式数据类型变化,也不用考虑变量的引用地址。
var a = "1" + 1; var b = "11" ; alert(a===b); //返回true
【示例7】表达式(a > b || a == b)与表达式(a >= b)并不完全相等。
var a = 1; var b = 2; alert((a>b||a==b)==(a>=b)) //返回true,此时似乎相等
如果为变量a和b分别赋值为null和undefined,则返回值为false,说明这两个表达式并非完全等价。
var a = null; var b = undefined; alert((a>b||a==b)==(a>=b)) //返回false,表达式的值并非相等
因为null==undefined等于true,所以(a > b || a == b)表达式返回值就为true。但是表达式null>=undefined返回值为false。