首页 » 性感的程序员 » JavaScript中的几个奇怪操作符

JavaScript中的几个奇怪操作符

注:原文出自《JavaScript for PHP developers》,博主只是根据自己的理解增加了一些内容.

本文主要介绍几个JavaScript中的几个奇怪的操作符,并与PHP中的类似操作符进行比较.这些操作符又:in,字符串连接,类型强制转换,void,逗号操作符.

1.in

1.1 for-in循环

说in操作符之前,不得不说一下for-in循环.在JavaScrip中当我们需要关联一个数组的时候,我们使用对象.并且,我们使用for-in循环而不是foreach来遍历数组.

假设我们在PHP中定义了如下的数组:

//PHP
$clothes = array(
    'shirt' => 'white', 
    'pants' => 'blue',
    'shoes' => 'black', //结尾建议加上逗号,这样要添加一个新单元时更方便 
);

//自PHP5.4起
$clothes = [
    'shirt' => 'white',
    'pants' => 'blue',
    'shoes' => 'black', //结尾建议加上逗号,这样要添加一个新单元时更方便 
];

在JavaScript中,相同的数据如下所示:

//JavaScript
var clothes = {
    shirt : 'white',
    pants : 'blue',
    shoes : 'black' //由于旧的IE的存在,结尾放逗号的话会出问题
} 

//上面的JavaScript是直接定义的对象.也可直接定义数组.在JavaScript中,数组也是对象.
//数组定义方式如下:
var clothes = new Array();
clothes['shirt'] = 'white';
clothes['pants'] = 'blue';
clothes['shirt'] = 'black';
typeof clothes;//"object"

在PHP中我们像下面这样遍历数组:

//PHP
$result = '';
foreach ($clothes as $key => $value) {
    $result .= $key . ':' . $value . '\n';
}

在JavaScript中我们使用for-in循环:


//JavaScript
var result ='';
for (var key in clothes) {
    result += key + ':' + clothes[key] . '\n';
}   

在该循环中,我们不能直接访问下一个属性的值,因此,我们使用方括号表示法clothes[key]来获取值.

还要注意,枚举属性的顺序不是固定的并且依赖于具体实习.换句话说,shoes可能出现在shirt之前,尽管其在定义中位于后面.如果想要保持这个顺序,我们需要使用一个常规的数组来存储数据.

这里只是为了说明,如果你暂时忘了PHP中的foreach必须使用=>来访问值,你也可以在PHP中像下面这样做,以模拟JavaScript中的for-in循环:


$result = '';
foreach (array_keys($clothes) as $key) {
    $result .= $key . ':' .$clothes[$key] . '\n';
} 

1.2.in

在前面in操作符用来遍历一个对象的属性.它也可用来检查一个对象中是否存在某个属性:

if ('shirt' in clothes) { //true
    //do something
}
if ('hat' in clothes) { //false
    //do something
}

也可用如下代码来进行检查:

if (clothes['shirt']) { //true
    //do something
}

或者,更常用的方法是使用点表示法

if (clothes.shirt) { //true
    //do something

}

不同指出在于,in只是检查该属性是否存在,他根本不会查看其值.使用clothes.shirt检查,只是在该属性存在且其值为非假的时候,才返回true.

例如,如果我们添加一个新的属性:

clothes.jacket = undefined;

那么:


'jacket' in clothes; //true

但是:


clothes.jacket; //undefined
!!clothes.jacket; //false

因为clothes.jacket的值是undefined,这是一个假值,并且会强制转换为false.

这类属于PHP中isset()和empty()的区别.

此外,更麻烦一点,我们可以四月typeof操作符来只检查属性是否存在二不检查其值:

typeof clothes.jacket !== "undefined"; //true

//但是请注意,当一个属性是`undefined`值的时候,相应的就会得到false
clothes.i_am_undefined = undefined;
typeof clothes.i_am_undefined === typeof clothes.i_dont_exist; //true

这种写法的一种更简单的方式是,与undefined值比较:

clothes.jacket !== undefined; //true

2.字符串连接

在PHP中我们使用.操作符来连接字符串.在查看for-in循环的时候,你可能已经注意到了,JavaScript中+操作符来连接字符串:

var alphabet = 'a' + 'b' + 'c';
alphabet; //"abc" 

这可能有些奇怪,但是+操作符既可用来将数字相加,也可用来连接字符串:

var numbers = '1' + '2' + '3';
var sum = 1 + 2 + 3;
numbers; //"123"
sum; //6

那么,我们如何知道该执行哪一种操作呢?这取决于操作数的类型.如果操作数是字符串,那么+就是连接字符串;如果操作数是数字,那么+就是求和.

不必说,+操作符经常会导致错误,因此,记住变量类型就很重要.

如果在计算和的时候,操作数是字符串,或者不清楚操作数的类型,可使用parseFloat()或parseInt()方法将字符串类型转换为数字类型,然后再求和:

var a = '1', b = '2', c = '3';
sum = parseFloat(a) + parseFloat(b) + parseFloat(c); //6

对于连接字符串,一种替代方法是,将要添加的字符串存储到一个数组中,完成之后,再将数组的元素连接起来.这种方式在较早的浏览器例如IE7甚至更早的版本中都能很好的工作:

['R', '2', '-', 'D', '2'].join(''); //"R2-D2"

最后,还可以使用contact()方法,该方法不需要我们为了连接字符串二创建临时的数组对象:


''.contact('R', '2', '-', 'D', '2'); //"R2-D2"
String.prototype.contact('R', '2', '-', 'D', '2'); //"R2-D2"

3.类型强制转换

由于+既可用于加法,也可用于字符串连接,我们也可用+来快速的转换变量的类型:

+'1'; //将字符串"1"转换为数字1
''+1; //将数字1转换为字符串"1"

这样,我们就可以像下面这样连接字符串或者求和:


var numbers = ''+1 + ''+2 + ''+3; 
var sum = +'1' + +'2' + +'3';
numbers; //"123"
sum; //6

说到强制转换,我们可以使用!!将变量转换为布尔类型:


!!1; //true
!!''; //false

第一个!取反,并且如果该值是假的话,会返回一个布尔true;第二个!再次取反,得到转换为布尔类型后我们想要的结果.此外,内建的构造函数也可用来执行变量的强制转换:


Number('1') === 1; //true
String(100) === '100'; //true
Boolean(0) === false; //true
Boolean(100) === true; //true

4.void

我们可能会遇到的另一个操作符是void,它接受任意的表达式作为操作数,并且返回undefined:

var a = void 1;
typeof a === 'undefined'; //true

void操作数很少用到,它会用作链接红的href.和typeof操作符一样,人们常常错误的将其与分组操作符()一起使用,这使其看上去像是一个函数调用.

有时候,typeof()用作一个函数,但是,不建议这么做.记住,typeof不是一个函数,而是一个操作符.在这种用法中,typeof()之所以像一个函数一样使用,是因为()也是一个操作符,它叫做分组操作符(grouping operator),通常用来覆盖操作优先级.例如:

3 * (2 + 1); //9
3 * 2 + 1; //7

<!--这不是一个好的做法-->
<a href="javascript:void(0)">Click and Nothing Happens</a> 
 

这中糟糕的做法看上去是挺无辜的,但是,你思考一下就会发现,这么做确实很傻.在这个过程中,发生了如下的使其:

  1. 用户单击,计算一个JavaScript表达式
  2. 直接量0作为一个操作数发送给分组操作符()
  3. 分组操作符返回数组中的最终值0
  4. 现在发送给void操作符
  5. void在这里是一个黑洞,它接受操作符并返回undefined

即便不考虑这种什么也不是的链接的糟糕语义,人们还是会将herf设置为javascript:undefined.

JavaScript中的typeof(a)typeof a的关系,就像PHP中echo ($a);echo $a;的关系(尽管使用二者的原因不同).PHP中的include($a)include $a也是基于同样的道理.即使这种写法有效,大妈仍然被看做是一种糟糕的写法,因为它有点鱼目混珠.

5.逗号操作符

逗号操作符是另一个奇怪的操作符,它是JavaScript中优先级最低的操作符,它直接返回传递给它的最后一个操作数的值:


var a = ('hello', 'there');
a; //"there"
var a = ('hello', 'there', 'young', 'one');
a; //"one"

它类似于&&和||,然而,当结果一目了然的时候,这些表达式会停止计算,但是逗号操作符会继续计算:

0 && 2 && 1; //0
0 || 2 || 1; //2
0 , 2 , 1, //1  

当JavaScript只期望一个表达式,而你想要偷偷插入另一个表达式的时候,逗号操作符就很有作用了.

你是否注意到,前面的例子中,&&和||并不总是像PHP那样返回一个布尔值,.相反,它们返回想要表达式的值.这可能有点令人混淆,特别是在如下的常用模式中,也按照默认情况编写JavaScript的时候:

//JavaScript
var a = 100;
var b = a || 200;
b; //100

//PHP
$a = 100;
$b = $a || 200;
var_dump($b); //bool(true)