操弄数值的运算符


对于运算符的使用,最主要是要注意自动类型转换的问题,其中有关+-*/以及=====!=!==)的说明,在〈弱类型的代价〉有先作过一些说明。

+两边的运算数有一个是字符串时,就会作字符串的连接,而整个表达式中有数字也有字符串时,要注意运算顺序。例如:

> 1 + 2 + '3';
'33'
> '1' + 2 + 3;
'123'
> '1' + (2 + 3);
'15'
>

第一个式子是先作1 + 2的运算,结果再与'3'作字符串的连接,得到'33'的字符串;第二个式子是先作字符串的连接,得到'12',再与 3 作字符串的连接,得到'123'的字符串;不确定的话,可如第三个式子,使用()定义优先运算顺序。

在比较运算上,除了〈弱类型的代价〉中提到的使用=====!=!==之外,还可以使用>>=<<=,在 JavaScript 中,这些运算符不仅可用在比较数字,还可以用来比较字符串,如果运算符两边都是字符串,则逐字符依 Unicode 码进行比较。

但如果>>=<<=两边一个是字符串,一个是数字,那么类型转换又有可能自动发生。如果字符串的部份代表数字,则会转换为数字,再与另一数字进行比较。如果字符串的部份不代表数字,则会被转换为NaN,与另一数字比较的结果自然就是false

>>=<<=两边其实可用于对象,比较结果视对象的valueOf方法内容而定,例如返回数字,则以返回的数字相比。例如Date就是一个例子:

> var date = new Date();
undefined
> date.valueOf();
1397699040389
> date > 1397699040389;
false
> date > 1397699040388;
true
> date > new Date();
false
> new Date() > date;
true
> var obj = {
...     valueOf : function() {
.....       return 100;
.....   }
... };
undefined
> 1 + obj;
101
> 1 > obj;
false
>

正如上例所示,其他表达式若需转为数值,也可以透过valueOf获取值,默认valueOf会返回实例本身。如果你没有重新定义valueOf,就会使用实例本身作比较。

> var o1 = {};
undefined
> o1.valueOf();
{}
> o1 === o1.valueOf();
true
>

注意,===用来比较对象时,是比较是否参考同一对象;==得留意两边的运算数,是否有类型转换后再进行比较的可能性。

如果你要测试某个对象上是否有某个特性,且要返回truefalse的结果,则可以使用in运算符。例如:

> 'x' in {x : 10};
true
>

之后还会详细介绍对象,在这边也可以看到,对象上的特性名称,实际上是个字符串。

如果你想要得知某个对象是否由哪个构造函数(Constructor,或所谓的类,虽然类这名词并不精确)所产生,则可以使用instanceof表达式。例如:

> [] instanceof Array;
true
> [] instanceof Object;
true
> [] instanceof Date;
false
>

对于没有继承关系的,instanceof会返回false

typeof也常用来测试对象类型,返回值是字符串,对于基本数据类型,数值会返回'number'、字符串会返回'string'、布尔会返回'boolean'、对于Function实例会返回'function'、对于undefined会返回'undefined'、对于其他对象一律返回'object',包括null也是返回'object'

> typeof 1;
'number'
> typeof '';
'string'
> typeof true;
'boolean'
> typeof function() {};
'function'
> typeof undefined;
'undefined'
> typeof {};
'object'
> typeof null;
'object'
>

&&||大家都知道用来判断 AND 与 OR 关系是否成立,而且具有短路运算,例如&&只要左运算数可以判断为不成立,则&&结果直接不成立,不用判断右运算数,而||只要左运算数判断为成立,就直接判断||结果为成立,不用再判断右运算数。

不过,&&||其返回值并非truefalse,而是在判断式整个可以确认是否成立时,返回当时的运算数。例如:

> 'left' && 'right';
'right'
> 0 && 'right';
0
> 'left' && 0;
0
>

在上面第一个例子中,左运算数非空字符串,会当作结果成立,所以再判断右运算数,也非空字符串,所以判断整个&&成立,由于是停在第二个运算数,所以返回'right'。第二个例子,由于 0 会被当作不成立,此时不用判断右运算数,就可判断整个&&运算不成立,所以直接返回 0。 第三个例子,由于左运算数非空字符串,会当作结果成立,所以再判断右运算数为 0,所以当作不成立,整个&&运算此时确认不成立,返回右运算数。

||的例子则如下:

> 'right' || 'left';
'right'
> 0 || 'left';
'left'
> 'right' || 0;
'right'
>

这个特性很有用,例如,想要在某个值存在时直接使用,而不存在时提供默认值,则可以如下:

function doSome(arg) {
    var option = arg || 'default';
    return option;
}

console.log(doSome());              // default
console.log(doSome('caterpillar')); // caterpillar

上面用到了函数作为范例,之后还会详细说明,像是如果函数参数很多时,还可以合并对象的方式提供默认值。上例其实就相当于使用?:运算符的结果:

function doSome(arg) {
    var option = arg ? arg : 'default';
    return option;
}

console.log(doSome());              // default
console.log(doSome('caterpillar')); // caterpillar

两者可以达到相同的效果,不过惯例上还是使用||的方式。

void运算符放在任何数据或表达式之前,都会产生undefined,这是获取undefined的另一个方式,在一些无法直接在程序中写undefined来获取undefined值的环境中,可以使用void来获取。例如:

> void 0;
undefined
> typeof void 0;
'undefined'
>




展开阅读全文