Jun 11

[原]JavaScript 的in 操作符 多云

linuxing , 13:52 , 编程 » JavaScript , 评论(0) , 引用(0) , 阅读(27638) , Via 本站原创 | |
    在编写JavaScript时,遇到一个常见的问题“如何判断某值是否数组中的元素”?这让我想起了PHP中的in_array()函数和Python中in 操作符。但JavaScript似乎没有内置类似的函数,而其in 操作符的作用也有点不同。通过查询相关的资料,我发现JavaScript的in 操作符还是挺有用的。

一、问题
让我想到in 操作符,正是因为这样一个问题:“如何判断某值是否数组中的元素”?
在PHP中,您可能会这样来处理:

$os = array("Mac", "NT", "Irix", "Linux");
if (in_array("Irix", $os)) {
    echo "Got Irix";
}

Python 中,可能会是这样:

val = 17
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 的右边必须是对象变量,例如:

var mycar = {make: "Honda", model: "Accord", year: 1998};
if ( "make" in mycar ) document.write('true');
  else document.write('false');  // 显示true

2、错误的用法
若我们把in 用于数组的判断时,会产生错误结果:

var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
if ( "oak" in trees ) document.write('true');
  else document.write('false');  //显示false

反过来,我们把trees数组看成一个对象,然后判断对象中的元素,例如:

if ( 0 in trees ) document.write('true');
  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、通过循环来解决问题
其实,这是处理“如何判断某值是否数组中的元素”问题的最基本方法:

function in_array(searchString,array) {
  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 判断。以下代码参考自:这里

function oc(a)
{
  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 语句在多个“或”条件情况时的写法。
例如,下面一句:

if ( foo == 'bar' || foo == 'foobar' || foo == 'foo' )
{
//...
}

就可以写成:

if ( foo in { 'bar':'', 'foobar':'', 'foo':'' } )
{
//...
}

判断结果相同。

四、注意事项
使用in 操作符时,除了小心区分数组与对象的区别外,还需要注意:
1、in 面向的必须是对象
例如,下面对字符串的判断中:

var color1 = new String("green");
"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删除对象的属性值:

var mycar = {make: "Honda", model: "Accord", year: 1998};
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:

var mycar = {make: "Honda", model: "Accord", year: 1998};
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),而普通数组元素就对应对象的属性(值为空)的情况。

var oneArray=new Array();
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]);
}

这样,有以下优势:
引用
a、我们就可以非常方便的利用in 来判断元素是否在对象中;
b、对象中检索属性,例如:o['oak'],其时间复杂度为O(1),而要在数组中找一个元素,时间复杂度为O(n)。

不过,也不说所有的数组都可以用对象来代替的。至少,必须要求数组中元素是唯一的。
例如,下面的数组:

var trees = new Array("redwood", "bay", "cedar", "oak", "maple","oak");

因为"oak"元素重复了,就不能直接等转换为某个对象。

4、效率问题
根据介绍,见:这里。其中提出:
集合的遍历效率(从高到低)为:var value = obj[key]; > for ( ; ; ) > for ( in )。
所以说,如果数组能用对象代替(值唯一),应首选对象形式。当遇到“判断某值是否数组中的元素”时,直接判断该值obj.key == 'undefined',或if( 'key' in obj )即可。否则,用for(;;)方式判断吧。
(对象没有length,不能用for(;;)循环,只能用for(in))
另外,在:这里,也提到了一个遍历数组的效率问题。其中提出,循环前,把数组的length先赋值个某变量后,循环时直接调用,这样效率会更高。

5、测试页面
五、参考文档
in Operator
Testing for a Value in JavaScript Array
javascript数组操作大全,数组方法总汇
遍历JavaScript对象的所有属性
js中遍历数组的效率问题
Tags: , ,
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   游客无需密码
网址   电邮   [注册]