本文全部代碼都在 node v0.10.28
中測試經過,由於node用的也是v8的javascript引擎,因此理論上來講在chrome中的表現應該一致,其它引擎各位能夠本身測試javascript
咱們先定義一個對象來進行比較java
function foo() { this.name = "foo"; }
再定義一個函數來比對node
function compare(f) { console.log("\ncompare with number:"); console.log("number f == 1: %s", f == 1); console.log("number f == 0: %s", f == 0); console.log("\ncompare with string:"); console.log("string f == \"\" : %s", f == ""); console.log("string f == \"foo\" : %s", f == "foo"); console.log("\ncompare with boolean:"); console.log("boolean f == true : %s", f == true); console.log("boolean f == false : %s", f == false); console.log("\ncompare with object:"); console.log("object f == {} : %s", f == {}); }
compare(new foo());
輸出結果:chrome
compare with number: number f == 1: false number f == 0: false compare with string: string f == "" : false string f == "foo" : false compare with boolean: boolean f == true : false boolean f == false : false compare with object: object f == {} : false
這個結果你們基本上都能理解函數
此次咱們給這個對象添加一個方法 valueOf
而後再來進行比較看看測試
foo.prototype.valueOf = function() { return 0; };
compare(new foo());
結果爲:this
compare with number: number f == 1: false number f == 0: true compare with string: string f == "" : true string f == "foo" : false compare with boolean: boolean f == true : false boolean f == false : true compare with object: object f == {} : false
這個結果咱們發現prototype
這三種狀況返回 true
日誌
這個結果讓人很差理解 咱們在valueOf方法中加入一些輸出再來看看code
foo.prototype.valueOf = function() { console.log('valueOf: '+ this.name); return 0; };
compare(new foo());
輸出結果爲:
compare with number: valueOf: foo number f == 1: false valueOf: foo number f == 0: true compare with string: valueOf: foo string f == "" : true valueOf: foo string f == "foo" : false compare with boolean: valueOf: foo boolean f == true : false valueOf: foo boolean f == false : true compare with object: object f == {} : false
如今咱們能夠猜想一下了, javascript在進行對象和基本數據類型(暫且把string也當作一種基本數據類型,下面說基本數據類型的時候也會帶上string)比較的時候,會調用對象的valueOf方法的返回值來進行比較.
這樣就能夠解釋number比較中爲何和0比較是true了, 可是還有和空字符串比較是true,和false比較是true,這裏個人理解是 javascript在數字和字符串以及boolean進行比較的時候,會轉換成數字後進行比較,因此 0 == ""
和 0 == false
也是true
只有最後一個和對象比較的時候沒有打印 valueOf: foo
因此也能夠認爲是對象比較時,只比較引用地址,理論上來講,對象比較 == 和 === 應該是同樣的,例如以下代碼:
var b1 = new Boolean(false); var b2 = new Boolean(false); console.log(b1 == b2); console.log(b1 === b2);
輸出兩次false
此次咱們將valueOf方法再修改一下,返回不是基本數據類型試一下,就返回本身吧
foo.prototype.valueOf = function() { console.log('valueOf: '+ this.name); return this; };
compare(new foo());
輸出結果爲:
compare with number: valueOf: foo number f == 1: false valueOf: foo number f == 0: false compare with string: valueOf: foo string f == "" : false valueOf: foo string f == "foo" : false compare with boolean: valueOf: foo boolean f == true : false valueOf: foo boolean f == false : false compare with object: object f == {} : false
此次和第一次比較沒什麼出入,只是打印了一些方法調用日誌而已,結果也理所固然的應該這樣了.
可是javascript爲何沒有遞歸調用咱們的valueOf
方法呢,按道理咱們返回了本身,而後它進行比較的時候應該再次調用valueOf
的
此次咱們再加入一個toString方法來看看
foo.prototype.toString = function(){ console.log(this.name + " : toString"); return this.name; }
compare(new foo());
輸出結果爲:
compare with number: valueOf: foo foo : toString number f == 1: false valueOf: foo foo : toString number f == 0: false compare with string: valueOf: foo foo : toString string f == "" : false valueOf: foo foo : toString string f == "foo" : true compare with boolean: valueOf: foo foo : toString boolean f == true : false valueOf: foo foo : toString boolean f == false : false compare with object: object f == {} : false
咱們發現每次輸出valueOf
的後面都跟隨了一個toString
的調用.
也就是說 javascript在調用valueOf後發現不是基本數據類型的時候,會調用toString的返回值再來進行比較 和咱們觀測到的結果一致,只有 f== "foo"
的結果是true
這樣也能夠解釋爲何沒有遞歸調用咱們的valueOf
方法了
接下來咱們再狠一點,toString
咱們也返回本身,看看javascript會怎麼處理
修改toString
方法爲:
foo.prototype.toString = function(){ console.log(this.name + " : toString"); return this; }
compare(new foo());
此次的結果會在乎料以外的:
結果爲:
console.log("number f == 1: %s", f == 1); ^ TypeError: Cannot convert object to primitive value at compare (/home/0x0001/Desktop/test.js:25:38) at Object.<anonymous> (/home/0x0001/Desktop/test.js:41:1) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:906:3
結果報異常了
最後我以爲,javascript在將對象和基本數據類型進行比較的時候,會先調用valueOf
的返回值來進行比較,若是valueOf
返回的不是基本數據類型,那麼繼續調用toString
方法的返回值來進行比較, 若是toString
的返回值還不是基本數據類型,那麼就沒法比較了