JavaScript 的in 操作符 (“如何判斷某值是否數組中的元素”?)


  在編寫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先賦值個某變量后,循環時直接調用,這樣效率會更高。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM