1. 程式人生 > >JavaScript 的in 操作符 (“如何判斷某值是否陣列中的元素”?)

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先賦值個某變數後,迴圈時直接呼叫,這樣效率會更高。

轉載:https://www.cnblogs.com/yu-709213564/p/6580392.html