/

JavaScript 中物件比大小的依據到底是什麼?

前言

在 JavaScript 中很多比較的情況非常不符合邏輯,在今年 AIS3 (2019) pre-exam 中,有考到類似概念所引發的錯誤情形。於是記錄一下 JavaScript 在比較物件時到底是依據什麼規則。

先看幾種常見的情況

1
2
3
4
5
6
7
8
9
10
> 100 > 10
true
> 100 > "10" //(字串與數字比較,會將字串自動轉為數字來比較)
true
> "100" > "10" //(兩者都是字串,實際上是按照字母順序來比較,下面的例子較明顯。並不是將兩個字串轉成數字來比)
true
> "abc" > "aaa"
true
> "ab" > "ac"
false

物件的比較規則

來點科普

這次的重點在於兩個物件的比較是依據何者來比較,首先要先知道 JS 有幾種型態

  • null
  • undefined
  • boolean
  • number
  • string
  • symbol
  • object

所以 JS 的型態都在這七種之內。然而,除了 object 以外,都屬於基本型態(primitive data type)。

比較的依據

物件的比較流程為以下(若成功則停,失敗則往下一步):

  1. 呼叫物件內的 valueOf 方法求得 return 值(值必須為 primitive data type)

(若非 primitive data tpye 或是沒有 valueOf 方法則往下)

  1. 呼叫 toString 方法求得 return 值(值必須為 primitive data type)

(若非 primitive data tpye 或是沒有 valueOf 方法則往下)

  1. 拋出錯誤 (TypeError: Cannot convert object to primitive value)

進行實驗

  1. 實驗一 (object 內的 valueOf):
1
2
3
4
5
6
7
8
9
10
let obj = {
valueOf() {
return 123;
},
toString() {
return {};
}
};
if (obj > 100) console.log("great!");
//output: great!
  1. 實驗二 (valueOf 回傳值不是 primitive data type):
1
2
3
4
5
6
7
8
9
10
11
let obj = {
valueOf() {
return {};
},
toString() {
return 123;
}
};

if (obj > 100) console.log("great!");
//output: great!
  1. 實驗三 (valueOf 與 toString 的比較順序):
1
2
3
4
5
6
7
8
9
10
11
12
let obj = {
valueOf() {
return 200;
},
toString() {
return 50;
}
};

if (obj > 100) console.log("great!");
else console.log("QQ");
//output: great!
1
2
3
4
5
6
7
8
9
10
11
12
let obj = {
valueOf() {
return 50;
},
toString() {
return 200;
}
};

if (obj > 100) console.log("great!");
else console.log("QQ");
//output: QQ
  1. 實驗四(兩者回傳值都非為 primitive data type,拋出錯誤)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let obj = {
valueOf() {
return {};
},
toString() {
return {};
}
};

if (obj > 100) console.log("great!");
//output:
//if (obj > 100) console.log("great!");
// ^

//TypeError: Cannot convert object to primitive value
// at Object. (/Users/yiyuchang/dev/tmp/article/example.js:10:9)
// ......

物件預設的 valueOf, toString

1
2
3
4
5
6
7
8
9
let obj = {};
console.log(obj.valueOf());
console.log(obj.toString());
if (obj == "[object Object]") console.log("great!");
//output:
//
//{}
//[object Object]
//great!

預設情況下物件是的 valueOf 是回傳空物件 {},而 toString 則是回傳 [object Object] 字串!

結論

希望這篇物件比較的規則說明有幫助到大家,javascipt 真是一門神奇的語言(?) 😄