操弄數值的運算子
July 22, 2022對於運算子的使用,最主要是要注意自動型態轉換的問題,其中有關 +
、-
、*
、/
以及 ==
及 ===
(!=
與 !==
)的說明,在〈弱型別的代價 – WAT!〉有先作過一些說明。
運算時的型態轉換
當 +
兩邊的運算元有一個是字串時,就會作字串的串接,而整個運算式中有數字也有字串時,要注意運算順序。例如:
> 1 + 2 + '3';
'33'
> '1' + 2 + 3;
'123'
> '1' + (2 + 3);
'15'
>
第一個式子是先作 1 + 2
的運算,結果再與 '3'
作字串的串接,得到 '33'
的字串;第二個式子是先作字串的串接,得到 '12'
,再與 3 作字串的串接,得到 '123'
的字串;不確定的話,可如第三個式子,使用 ()
定義優先運算順序。
在比較運算上,除了〈弱型別的代價 – WAT!〉中提到的使用 ==
、===
、!=
、!==
之外,還可以使用 >
、>=
、<
、<=
,在 JavaScript 中,這些運算子不僅可用在比較數字,還可以用來比較字串,如果運算子兩邊都是字串,逐字元依 Unicode 碼點進行比較。
但如果 >
、>=
、<
、<=
兩邊一個是字串,一個是數字,那麼型態轉換又有可能自動發生。如果字串的部份代表數字,則會轉換為數字,再與另一數字進行比較。如果字串的部份不代表數字,則會被轉換為 NaN
,與另一數字比較的結果自然就是 false
。
valueOf、toString
>
、>=
、<
、<=
兩邊其實可用於物件,比較結果視物件的 valueOf
方法內容而定,例如傳回數字,則以傳回的數字相比。例如 Date
就是一個例子:
> var date = new Date();
undefined
> date.valueOf();
1397699040389
> date > 1397699040389;
false
> date > 1397699040388;
true
> date > new Date();
false
> new Date() > date;
true
> var obj = {
... valueOf : function() {
..... return 100;
..... }
... };
undefined
> 1 + obj;
101
> 1 > obj;
false
>
正如上例所示,其他運算式若需轉為數值,也可以透過 valueOf
取得值,預設 valueOf
會傳回 toString
的傳回值。如果你沒有重新定義 valueOf
,就會使用 toString
的傳回值作比較。
> var o1 = {};
undefined
> o1.valueOf();
{}
> o1 === o1.valueOf();
true
>
注意,===
用來比較物件時,是比較是否參考同一物件;==
得留意兩邊的運算元,是否有型態轉換後再進行比較的可能性。
探查物件
如果你要測試某個物件上是否有某個特性,且要傳回 true
、false
的結果,則可以使用 in
運算子。例如:
> 'x' in {x : 10};
true
>
之後還會詳細介紹物件,在這邊也可以看到,物件上的特性名稱,實際上是個字串。
如果你想要得知某個物件是否由哪個建構式(Constructor)產生,則可以使用 instanceof
運算式。例如:
> [] instanceof Array;
true
> [] instanceof Object;
true
> [] instanceof Date;
false
>
對於沒有繼承關係的,instanceof
會傳回 false
。
typeof
也常用來測試物件型態,傳回值是字串,對於基本資料型態,數值會傳回 'number'
、字串會傳回 'string'
、布林會傳回 'boolean'
、對於 Function
實例會傳回 'function'
、對於 undefined
會傳回 'undefined'
、對於其他物件一律傳回 'object'
,包括 null
也是傳回 'object'
。
> typeof 1;
'number'
> typeof '';
'string'
> typeof true;
'boolean'
> typeof function() {};
'function'
> typeof undefined;
'undefined'
> typeof {};
'object'
> typeof null;
'object'
>
&&
與 ||
大家都知道用來判斷 AND 與 OR 關係是否成立,而且具有捷徑運算,例如 &&
只要左運算元可以判斷為不成立,則 &&
結果直接不成立,不用判斷右運算元,而 ||
只要左運算元判斷為成立,就直接判斷 ||
結果為成立,不用再判斷右運算元。
不過,&&
或 ||
其傳回值並非 true
或 false
,而是在判斷式整個可以確認是否成立時,傳回當時的運算元。例如:
> 'left' && 'right';
'right'
> 0 && 'right';
0
> 'left' && 0;
0
>
在上面第一個例子中,左運算元非空字串,會當作結果成立,所以再判斷右運算元,也非空字串,所以判斷整個 &&
成立,由於是停在第二個運算元,所以傳回 'right'
。第二個例子,由於 0 會被當作不成立,此時不用判斷右運算元,就可判斷整個 &&
運算不成立,所以直接傳回 0。 第三個例子,由於左運算元非空字串,會當作結果成立,所以再判斷右運算元為 0,所以當作不成立,整個 &&
運算此時確認不成立,傳回右運算元。
||
的例子則如下:
> 'right' || 'left';
'right'
> 0 || 'left';
'left'
> 'right' || 0;
'right'
>
這個特性很有用,例如,想要在某個值存在時直接使用,而不存在時提供預設值,則可以如下:
function doSome(arg) {
var option = arg || 'default';
return option;
}
console.log(doSome()); // default
console.log(doSome('caterpillar')); // caterpillar
上面用到了函式作為範例,之後還會詳細說明,像是如果函式參數很多時,還可以合併物件的方式提供預設值。上例其實就相當於使用 ?:
運算子的結果:
function doSome(arg) {
var option = arg ? arg : 'default';
return option;
}
console.log(doSome()); // default
console.log(doSome('caterpillar')); // caterpillar
兩者可以達到相同的效果,不過慣例上還是使用 ||
的方式。
void 運算
void
運算子放在任何資料或運算式之前,都會產生 undefined
,這是取得 undefined
的另一個方式,在一些無法直接在程式中寫 undefined
來取得 undefined
值的環境中,可以使用 void
來取得。例如:
> void 0;
undefined
> typeof void 0;
'undefined'
>