本文全部代码都在 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
的返回值还不是基本数据类型,那么就没法比较了