在编写JavaScript时,遇到一个常见的问题“如何判断某值是否数组中的元素”?这让我想起了PHP中的in_array()函数和Python中in 操作符。但JavaScript似乎没有内置类似的函数,而其in 操作符的作用也有点不同。通过查询相关的资料,我发现JavaScript的in 操作符还是挺有用的。
一、问题
让我想到in 操作符,正是因为这样一个问题:“如何判断某值是否数组中的元素”?
在PHP中,您可能会这样来处理:
if (in_array("Irix", $os)) {
echo "Got Irix";
}
Python 中,可能会是这样:
if val in [1,4,5,7,12,14,17,20,34]: print "yes"
那JavaScript中该如何操作呢?先来看看in 操作符的说明。
二、in 操作符
现在写JavaScript时,我喜欢参考两个地方:MDC 的Core JavaScript 1.5 Reference 和 W3Schools 的JavaScript Tutorial。
从这里,可找到in Operator的说明。可见,JavaScript中的in 操作符是对Object(对象)操作的,并不是针对数组。
1、简单用法
in 的右边必须是对象变量,例如:
if ( "make" in mycar ) document.write('true');
else document.write('false'); // 显示true
2、错误的用法
若我们把in 用于数组的判断时,会产生错误结果:
if ( "oak" in trees ) document.write('true');
else document.write('false'); //显示false
反过来,我们把trees数组看成一个对象,然后判断对象中的元素,例如:
else document.write('false'); //显示true
document.write(trees.length); //显示trees数组对象的length属性值:5
if ( 'length' in trees ) document.write('true');
else document.write('false'); //显示true,因为length是trees数组对象的属性
三、对数组判断的正确方法
虽然in 直接在用于判断数组时会产生错误结果,但也不是没有办法可以避免的。合适地使用in 操作符反而可以带来便利。
1、通过循环来解决问题
其实,这是处理“如何判断某值是否数组中的元素”问题的最基本方法:
for (i=0;i<array.length;i++) {
if ( searchString == array[i] ) return true;
}
return false;
}
if ( in_array('oak',trees) ) document.write('true'); //显示true
else document.write('false');
2、合适的利用in 操作符
既然我们知道in 可以用于判断对象的属性值,那么,同样的,我们可以把数组一一映射到对象的属性,然后再用in 判断。以下代码参考自:这里。
{
var o = {}; //相当于var o = new Object();
for(var i=0;i<a.length;i++)
{
o[a[i]]=''; //注意该写法,不能写成o.a[i]
}
return o;
}
if ( 'oak' in oc(trees) ) document.write('true'); //显示true
else document.write('false');
o = oc(trees);
if ( o.oak != 'undefined' ) document.write('true'); //显示true
else document.write('false'); //true
if ( o['oak'] != 'undefined' ) document.write('true'); //显示true
else document.write('false'); //true
这里,oc 函数把一个数组转换成对象,并把数组的元素作为对象的属性(值为空字符串),然后利用了in 操作符判断。
※ 注意:平时obj.key和obj['key']可以互通,但在for(;;)和for(in)语句中,对象属性的写法是obj['key'],而不是obj.key。
3、巧用in 操作符
除了数组情况下可借用in 操作符外,我们还可以利用in 的特性来简化if 语句在多个“或”条件情况时的写法。
例如,下面一句:
{
//...
}
就可以写成:
{
//...
}
判断结果相同。
四、注意事项
使用in 操作符时,除了小心区分数组与对象的区别外,还需要注意:
1、in 面向的必须是对象
例如,下面对字符串的判断中:
"length" in color1 // returns true
var color2 = "coral";
"length" in color2 // generates an error (color is not a String object)
因为JavaScript与Python不同,字符串并不能直接就处理为字符串对象。FireFox 中会报“invalid 'in' operand color2”,IE 中会报“缺少对象”。
2、对象属性被删除(deleted)或未定义(undefined)的判断结果是不同的
用delete删除对象的属性值:
delete mycar.make;
"make" in mycar; // returns false
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
delete trees[3];
3 in trees; // returns false
把对象属性值设置为undefined:
mycar.make = undefined;
"make" in mycar; // returns true
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
trees[3] = undefined;
3 in trees; // returns true
3、关联数组
既然数组可以转换为对象,我们就可以把JavaScript的对象看成是“关联数组”(类似Python中的字典、Perl中的Hash),而普通数组元素就对应对象的属性(值为空)的情况。
oneArray["firstKey"]="firstValue";
oneArray["secondKey"]="secondValue";
var oneObject={};
oneObject.firstKey="firstValue";
oneObject.secondKey="secondValue";
for ( key in oneArray ) {
document.write(key+'=>'+oneArray[key]);
}
for ( key in oneObject ) {
document.write(key+'=>'+oneObject[key]);
}
这样,有以下优势:
b、对象中检索属性,例如:o['oak'],其时间复杂度为O(1),而要在数组中找一个元素,时间复杂度为O(n)。
不过,也不说所有的数组都可以用对象来代替的。至少,必须要求数组中元素是唯一的。
例如,下面的数组:
因为"oak"元素重复了,就不能直接等转换为某个对象。
4、效率问题
根据介绍,见:这里。其中提出:
集合的遍历效率(从高到低)为:var value = obj[key]; > for ( ; ; ) > for ( in )。
所以说,如果数组能用对象代替(值唯一),应首选对象形式。当遇到“判断某值是否数组中的元素”时,直接判断该值obj.key == 'undefined',或if( 'key' in obj )即可。否则,用for(;;)方式判断吧。
(对象没有length,不能用for(;;)循环,只能用for(in))
另外,在:这里,也提到了一个遍历数组的效率问题。其中提出,循环前,把数组的length先赋值个某变量后,循环时直接调用,这样效率会更高。