javaScript 关于 == 那些事

本文全部代码都在 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

  • 和 0 比较
  • 和空字符串比较
  • 和false比较

这三种状况返回 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的返回值还不是基本数据类型,那么就没法比较了